3 ms·
It'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... Mod
by geokon 4y ago
It'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
- 4y ago