{"action":"created","issue":{"url":"https://api.github.com/repos/conda-forge/conda-forge.github.io/issues/389","repository_url":"https://api.github.com/repos/conda-forge/conda-forge.github.io","labels_url":"https://api.github.com/repos/conda-forge/conda-forge.github.io/issues/389/labels{/name}","comments_url":"https://api.github.com/repos/conda-forge/conda-forge.github.io/issues/389/comments","events_url":"https://api.github.com/repos/conda-forge/conda-forge.github.io/issues/389/events","html_url":"https://github.com/conda-forge/conda-forge.github.io/issues/389","id":226935421,"number":389,"title":"Use ccache","user":{"login":"gqmelo","id":12578273,"avatar_url":"https://avatars0.githubusercontent.com/u/12578273?v=3","gravatar_id":"","url":"https://api.github.com/users/gqmelo","html_url":"https://github.com/gqmelo","followers_url":"https://api.github.com/users/gqmelo/followers","following_url":"https://api.github.com/users/gqmelo/following{/other_user}","gists_url":"https://api.github.com/users/gqmelo/gists{/gist_id}","starred_url":"https://api.github.com/users/gqmelo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gqmelo/subscriptions","organizations_url":"https://api.github.com/users/gqmelo/orgs","repos_url":"https://api.github.com/users/gqmelo/repos","events_url":"https://api.github.com/users/gqmelo/events{/privacy}","received_events_url":"https://api.github.com/users/gqmelo/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":17,"created_at":"2017-05-08T04:35:47Z","updated_at":"2017-06-08T19:07:36Z","closed_at":null,"body":"This issue is intended to discuss the use of ```ccache``` when building compiled packages and the findings I've got on a [experimental branch](https://github.com/gqmelo/llvmdev-feedstock/pull/1).\r\n\r\n# Introduction\r\n\r\n> ccache is a compiler cache. It speeds up recompilation by caching previous compilations and detecting when the same compilation is being done again. Supported languages are C, C++, Objective-C and Objective-C++.\r\n\r\nFrom my personal experience ```ccache``` is very reliable and after a couple of years using it at work we never found any issue. Additionally adopting ccache was a huge improvement.\r\n\r\n# Why\r\n\r\nUsing ```ccache``` on ```conda-forge``` could bring a lot of benefits:\r\n\r\n- Faster feedback for mantainers of large packages. I personally find it very demotivating trying to make a large package build on CI.\r\n- Possibly decrease CI's queue size\r\n- Make it possible to build packages that exceed timeout limits\r\n\r\n# Obtained results\r\n\r\nWhen experimenting with [llvmdev-feedstock](https://github.com/gqmelo/llvmdev-feedstock/pull/1) the results were very promising.\r\n\r\n- On CircleCI a build with ```99.92%``` cache hit took ```15m``` as opposed to the usual ```1h30m```\r\n- On CircleCI a first-time build took about ```1h``` instead of the usual ```1h30m```. This happens because on CircleCI all package variations are built on the same job. \r\n- On Travis a build with ```99.92%``` cache hit took about ```14m``` instead of the usual ```44m``` (very close to the timeout limit).\r\n\r\n# Necessary changes\r\n\r\n## TravisCI\r\n\r\n```diff\r\n language: generic\r\n os: osx\r\n osx_image: xcode6.4\r\n \r\n+cache:\r\n+  branch: no-md5deep\r\n+  directories:\r\n+  - $HOME/.ccache\r\n+\r\n+\r\n env:\r\n   matrix:\r\n     \r\n```\r\n\r\nThe ```branch: no-md5deep``` is a workaround for https://github.com/travis-ci/travis-ci/issues/7456\r\n\r\n## CircleCI\r\n\r\n```diff\r\n   # just to pull each time. #rollondockercaching\r\n   override:\r\n     - docker pull condaforge/linux-anvil\r\n+    - ./ci_support/run_docker_build.sh || touch ./build_failed\r\n+  cache_directories:\r\n+    - \"./build_artefacts/.ccache\"\r\n \r\n test:\r\n   override:\r\n     # Run, test and (if we have a BINSTAR_TOKEN) upload the distributions.\r\n-    - ./ci_support/run_docker_build.sh\r\n+    - if test -f ./build_failed; then exit 1; fi\r\n```\r\n\r\nCircleCI cache is only done for the dependencies phase. So to cache the compilation we need to move the build command. Also, the build command cannot fail during the dependencies phase, otherwise the cache will not be saved. That is why the verification is done later.  \r\n\r\n## ccache setup\r\n\r\nThis would be added preferably to [toolchain activate script](https://github.com/conda-forge/toolchain-feedstock/blob/master/recipe/activate.sh):\r\n\r\n```bash\r\nif [ $(uname) == Linux ]; then\r\n    export CC=\"ccache gcc\"\r\n    export CXX=\"ccache g++\"\r\n    export CCACHE_DIR=/feedstock_root/build_artefacts/.ccache\r\n    # Set max cache size so we don't carry old objects for too long\r\n    ccache -M 400M\r\nelse\r\n    export CC=\"ccache clang\"\r\n    export CXX=\"ccache clang++\"\r\n    # Set max cache size so we don't carry old objects for too long\r\n    ccache -M 200M\r\nfi\r\nexport CCACHE_BASEDIR=\"${SRC_DIR}\"\r\nccache -z\r\n```\r\n\r\nNote the ```ccache -M``` commands to limit the cache size. This is important because the cache is never automatically deleted by TravisCI and CircleCI. Also we would want to set different sizes for both CI's as CircleCI builds more than one package per job.\r\n\r\nAlso ```ccache``` needs to be added as dependency, preferably on [toolchain package](https://github.com/conda-forge/toolchain-feedstock/blob/master/recipe/meta.yaml)\r\n\r\n## Recipes\r\n\r\nThere would be no necessary changes on recipes whose build systems respect ```CC``` and ```CXX``` variables. However for large packages that could exceed the timeout limit it would be desirable to avoid the timeout killing the build command. On Linux this can be achieved with something like:\r\n\r\n```bash\r\ntimeout 5400 make -j{CPU_COUNT}\r\n```\r\n\r\nAvoiding the timeout limits is important because otherwise the cache is not saved.\r\n\r\n# Windows\r\n\r\nOn Windows there is ```clcache``` which was inspired by ccache and so is very similar. The problem is that AppVeyor cache mechanism is different. The cache is only enabled for regular branchs, not PR's. Also it limits the cache size to 1GB per account, which in my opinion make the cache useless for a large organization as ```conda-forge```.\r\n\r\n# References\r\n\r\n- https://circleci.com/docs/1.0/how-cache-works/\r\n- https://docs.travis-ci.com/user/caching/\r\n- https://www.appveyor.com/docs/build-cache/\r\n\r\n# Pending\r\n\r\n- [ ] Make it work when someone build locally without ```run_docker_build.sh``` script"},"comment":{"url":"https://api.github.com/repos/conda-forge/conda-forge.github.io/issues/comments/307198358","html_url":"https://github.com/conda-forge/conda-forge.github.io/issues/389#issuecomment-307198358","issue_url":"https://api.github.com/repos/conda-forge/conda-forge.github.io/issues/389","id":307198358,"user":{"login":"gqmelo","id":12578273,"avatar_url":"https://avatars0.githubusercontent.com/u/12578273?v=3","gravatar_id":"","url":"https://api.github.com/users/gqmelo","html_url":"https://github.com/gqmelo","followers_url":"https://api.github.com/users/gqmelo/followers","following_url":"https://api.github.com/users/gqmelo/following{/other_user}","gists_url":"https://api.github.com/users/gqmelo/gists{/gist_id}","starred_url":"https://api.github.com/users/gqmelo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gqmelo/subscriptions","organizations_url":"https://api.github.com/users/gqmelo/orgs","repos_url":"https://api.github.com/users/gqmelo/repos","events_url":"https://api.github.com/users/gqmelo/events{/privacy}","received_events_url":"https://api.github.com/users/gqmelo/received_events","type":"User","site_admin":false},"created_at":"2017-06-08T19:07:36Z","updated_at":"2017-06-08T19:07:36Z","body":"Yeah, the scipy build system is doing something weird with the variable. It's weird that for it seems to handle it right for most commands.\r\n\r\nSo I think it's better to follow the symlink approach: https://ccache.samba.org/manual.html#_run_modes, then set the variables to the symlinks, or just add the symlinks to PATH (I would prefer to avoid that as it's more obscure)"}}
{"actor":{"display_login":"gqmelo"}}