Hi cmake list! I've been playing around with cmake for a couple of weeks now, and am loving (almost) every minute of it. A thing I really like about cmake and that I feel will add the greatest value for me, besides the cross-platform capabilities, is the "build products go outside the source tree" philosophy - that I can basically choose where I want the build products (and the OS-specific makefiles/project files) to go, just by choosing where I run the cmake command. I really want to not break this freedom while solving the problems that I have.
I'm working on making a suggestion at my company to move to cmake for our building needs, but I'm stuck on coming up with a cmake-way of handling some of the aspects of juggling more projects, targets and versions of them at the same time. Bear with me, I can't say that I've dug through everything there is to know about cmake, so if I need to just RTFM, that is a suitable answer, just point me to some specific command man pages that will help me. The scenario I wish to handle in an elegant way, is this: Suppose a company is working on 4 projects: App_A, App_B, Lib_C and Lib_D. The directory structure is very simple: Top |-App_A |-App_B |-Lib_C |-Lib_D Every one of the App/Lib folders has the following structure inside them: App_X/Lib_X |-include (for libs only, this is where the interface they expose to the outside world goes) |-src |-tests |-CMakeLists.txt The CMakeLists.txts in each of the App/Lib folders contain their own project, and add the subdirectories src and tests, which have their own CMakeLists.txts that just add the actual libraries or executables that they need. Each of the tests folders have two executables made, with target names unit_tests and integration_tests. Building each of these folders individually works fine, but I have the following dependencies: Lib_D depends on Lib_C App_A depends on Lib_C App_B depends on Lib_D So far I've been taking care of the dependencies "outside" of the cmake world - just by manually "including" and linking to hard coded folders where the outputs of each of the builds go. Which also means that I have to manually build Lib_C when someone checks in a change for it, while I'm working on Lib_D, and then build Lib_D. It would be nice to make cmake aware of these dependencies and automatically detect that Lib_C needs a rebuild when I build Lib_D. And it would be even nicer if the build folders did not have to be hard coded - if I could just run cmake anywhere, and would get the makefiles/project files for all of the Apps/Libs right there, _and_ they'd be aware of the dependencies they have. The closest I've gotten to it is by making a top level CMakeLists.txt (that would reside in the folder "Top" in the diagram above), has a TOP/ROOT project in it and just includes the subfolders of the individual Apps/Libs. If none of the projects and targets in any of the folders shared the same name, this would be the perfect solution that I'm looking for, but, alas, they do not - every project has a target called unit_tests and integration_tests. I could bite the bullet and work around by naming them Lib_C_unit_tests and so on, ONCE... but then, what if this happens: Suppose App_A is "done", that's it, no more new features, we want to lock it and only apply bug fixes, if needed. But since Lib_C is under constant development and becomes backwards incompatible every now and then in one way or another, we also want to lock down the version of Lib_C that was used when App_A was "done". So I copy the folder of Lib_C and name it Lib_C_v_1.2.3 or whatever, and add it to the top level CMakeLists.txt. I can understand having to go into that folder and rename the project and top level target from Lib_C to Lib_C_v_1.2.3, and then linking the frozen App_A to that instead of Lib_C. But now I have two targets called Lib_C_unit_tests and Lib_C_integration_tests - I need to rename those as well. OK, there's only two of them... but what if Lib_C is actually more complicated - it has many components which in turn have dependencies on each other - renaming all of those to get rid of the duplicates will be a pain, and we have to do this every time a lib or app branches (and in real life that happens a bit more often than in a scenario of a company that only has two apps and two libs). So - that's the problem. Can you guys suggest an elegant cmake style solution? I've thought about something like keeping a variable named ${VS} - version string, keeping it short since I'd have to use it a lot - every project and target would get named Lib_C_${VS} and Lib_C_${VS}_unit_tests and so on, and then each of the Lib_C/App_A folder CMakeLists.txt would overwrite the value of it, so that the CMakeLists.txt files in the src and tests folders and subfolders would name their targets and projects the right way. This could work, if we control all the libs that we link against, although it would introduce some clutter in the project and target names. But what if some of the libs are not under our control - say gtest or some other great open source lib that uses cmake (and I'm not even trying to solve the problem of libs that don't use cmake right now ;) ) - and the need to keep two copies of them arises, since two of our own projects might want to build and link against two different versions of gtest or some other lib. Going over their cmake files and renaming targets and projects would be _painful_ (not to mention wrong - don't mess with the lib source, just use it). Is there a way to make target and project names be "nested" instead of "always top level", with the side effect of cmake creating the makefiles/projects in a similar hierarchy and setting the dependencies up right? So that, for example, when I have the need to branch gtest, I could just make two folders, say, gtest_latest and gtest_1.2.3, in the Top level folder, stick an "umbrella" CMakeLists.txt in each of them, that creates the projects gtest_latest and gtest_1.2.3, and include the CMakeLists.txt gtest provides as a subfolder that creates a new project, gtest, inside each of those. If that were the case, I could, in App_A, that needs to use the old version of gtest, just say something along the lines of "when I say gtest I mean Top:gtest_1.2.3:gtest", and all the CMakeLists.txt in the subfolders of App_A, that do target_link_libraries(myTarget gtest) would select the right version of it. Also, if the names were nested, each of my projects could have their own target named unit_tests without fear of colliding. Now, I've googled plenty of posts online that try to address one or more sub-problems of the scenario I presented, but nothing that solves any real part of it in a _clean_ way - most of them are hackish and require a great deal of manual labor every time a certain event happens, such as renaming lots projects / targets when branching of a library happens, etc, which is exactly the problem I'm trying to eliminate. I may just be daydreaming of a solution that does not yet exist... in which case with your help we might be able to formulate a feature request for cmake. I believe cmake could use a solution (or if it exists, we need to shed some light on it in the public eye) for problems like this, since I've encountered way too many posts of people complaining about not being able to organize dependencies between projects in an elegant way. Anyway, looking forward to hearing how you handled similar problems - the perfect solution that I'm looking for might not exist, but I'll take a good tradeoff as well. Thanks, Gints -- Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://www.cmake.org/mailman/listinfo/cmake