3 ms·
For the build system, I like: http://cliutils.gitlab.io/modern-cmake/ http://cliutils.gitlab.io/modern-cmake/ In addition to building, it will show how to add
by galangalalgol 4y ago
For the build system, I like:
http://cliutils.gitlab.io/modern-cmake/ http://cliutils.gitlab.io/modern-cmake/
In addition to building, it will show how to add cppcheck and clang-tidy to your cmake files. That part is pretty easy. Just don't turn on every check in clang-tidy. Many of them are for specific code bases. Modernization checks are my favorite ones. Keeps you doing stuff the modern way.
My link has you doing dependency management with git submodules. That is a method still in use and even advocated for, but conan is often touted as the more modern way to do it. I've used it on some teams, and I'm undecided. I also have no good resources for it.
- geokon 4y agoIt's been quite a few years since I've really written any C++ and I'm surprised the landscape hasn't evolved at all. People are making the same mistakes... Modern CMake should be using toolchain files to specify the toolchain/flags. That should be included in ever CMake intro. (Hacking those into your CMakeLists.txt is not okay) gitsubmodules are also a hack 1: Many dependencies are not setup to be used as a CMake subdirectory. Variables such as the project-version-number get overwritten by the parent project and more dangerously the submodule can start to change variables in the overall project. 2: Dependencies will often reuse target names. For instance, libraries often have a target called `uninstall`. Because redeclaring a target in a different subdirectory is a no-no - CMake crashes Proper dependency management can be done directly through CMake without repeating yourself by using Hunter: https://hunter.readthedocs.io/ https://hunter.readthedocs.io/ This solved the diamond problem, gives you proper namespaces in CMake and with Polly you can have sane toolchain files (https://github.com/ruslo/polly https://github.com/ruslo/polly - but you can also just write them manually). Everything is built on CMake and Git (and git hashes). You get nice dependency build caches and forking dependencies is also trivial EDIT: The creator of Hunter has his own CMake Intro. I haven't gone through it while-learning, but it looks comprehensive and informative: https://cgold.readthedocs.io/en/latest/ https://cgold.readthedocs.io/en/latest/
- jcelerier 4y ago> Modern CMake should be using toolchain files to specify the toolchain/flags. That should be included in ever CMake intro. (Hacking those into your CMakeLists.txt is not okay) this so much. I made a toolchain generator to make myself toolchains with common set of flags (asan, lto, etc specified with a single simple word on the command line for each "feature" or at worst a "key=value" pair, e.g. "compiler=gcc", "linker=lld") and really it made my life so much better: https://github.com/jcelerier/cninja https://github.com/jcelerier/cninja
- galangalalgol 4y agoGit submodules are definitely a hack. My experience with conan has been unpleasant for several reasons, but mostly in regards to writing dependencies for code bases that use submodules and aren't interested in my team's suggestion they use conan. Vcpkg doesn't seem better, and probably a bit worse. Does hunter make this any easier?
- geokon 4y agoI'm not super clear what your question is. If the dependency you want to use has no dependencies of its own - then it can be used directly with no changes (as long it's CMakeLists.txt is sane and it can use a passed-in toolchain file) https://hunter.readthedocs.io/en/latest/creating-new/create/cmake.html https://hunter.readthedocs.io/en/latest/creating-new/create/... If the dependency has its own dependencies, then you need to "Hunterize" it - specify library versions, tweak the targets to use namespaces, etc. They're usually small changes. They have a huge list of Hunterized forks: https://hunter.readthedocs.io/en/latest/packages.html https://hunter.readthedocs.io/en/latest/packages.html Finally, a CMakeLists.txt that's been made to work with Hunter can always revert back and be run without Hunter. So the change isn't intrusive. https://hunter.readthedocs.io/en/latest/overview/compatibility.html https://hunter.readthedocs.io/en/latest/overview/compatibili... A minimal CMakelists.txt will look something like: HunterGate( URL "https://github.com/cpp-pm/hunter/archive/v0.23.297.tar.gz" SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3" ) project(Foo) hunter_add_package(Boost COMPONENTS regex system filesystem) find_package(Boost CONFIG REQUIRED regex system filesystem) add_executable(foo foo.cpp) target_link_libraries(foo PUBLIC Boost::regex Boost::system Boost::filesystem) The first block specifies the available package list (you can fork and host your own). If you disable Hunter this isn't used The line that reads `hunter_add_package` is the Hunter part that downloads and build the dependency (using the current toolchain file). But if you disable Hunter then that line would simply get skipped. In the third line `find_package` will run.. and if you had Hunter build the dependency then it'd use that as the target - otherwise it just runs like "normal CMake" and it tries to find the package elsewhere (like from your system package manager or whatever) If your dependency has its own dependencies as git submodules.. then I'm not super sure you have a very clean migration path b/c they will not be using `find_package` and will instead be using `add_subdirectory`. Maybe you could patch their CMakeLists.txt to use Hunter when explicitely enabled, and then drop down to `add_subdirectory` otherwise. It'd be a bit ugly but they would keep their workflow I guess. You'd need to check that their targets end up with the same namespaced names (with the :: notation) when seen from your project... I don't know off the top of my head how Hunter handles a subdirectory with a project name of it's own
- dongping 4y agoHonestly, I find the usage of the adjective "modern" deceptive and insincere in the marketing term "Modern CMake". The "modern" scripting language doesn't even support return values and the variables lack basic type-safety. It breaks for anything beyond a simple Hello World. I would recommend any other C++ build tools that use a proper programming language for scripting, be it Meson or Bazel.
- galangalalgol 4y agoI dislike cmake, so when a sibling post mentioned meson I went looking. It doesn't seem to have good support for cuda, and neither does bazel, to the point I don't immediately find anyone getting it to work. These days the only reason I start a project at work in c++ instead of rust is to use cuda, so that would be a strong consideration. Is this easier than my brief glance would indicate?
- dongping 4y agoI have yet to encounter problems with Cuda in our Bazel environment, but I don't have to maintain the Bazel rules, since our build infra team does that. I would think that rules like https://github.com/liuliu/rules_cuda https://github.com/liuliu/rules_cuda should work for you in Bazel. (Tensorflow also uses Bazel, so I don't think that this should be a problem.)