7

PREFACE: I am only talking about compiling locally, not about installing projects. This is because I haven't done enough research on proper install with CMake, though please chime in if my question directly relates to install practices (seems likely).

TL;DR

  1. In what scenarios do you not want to gather all project libraries being built into the same directory? Why doesn't anybody ever CACHE the CMAKE_*_OUTPUT_DIRECTORY paths?

  2. Is there ever a need to perform $<CONFIG> level specifications directly?

  3. Should the general default be to CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR, or PROJECT_BINARY_DIR?

1. To cache or not to cache?

From this excellent answer

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

which you see in many projects across the web.

  • A parent CMakeLists.txt cannot override these.
  • If a parent project wants to / needs to change these, e.g. to put all in the same folder, it is impossible.

So the suggested revision would be to always CACHE PATH "description":

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Where to place compiled static libraries.")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Where to place compiled shared libraries.")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Where to place compiled executables.")
  • Is there any reason not to cache?

2. Treatment of $<CONFIG> builds

This should pretty much always be left to the generator, yes? My understanding (and experience) is by setting the non-config one, generators (Visual Studio, XCode, ...) that use folders per-config build are still content to place things where they ordinarily would. AKA by not setting config level CMAKE_*_OUTPUT_DIRECTORY_* I am passing control to the generator to let it decide.

3. BINARY_DIR, CURRENT_BINARY_DIR, or PROJECT_BINARY_DIR?

On the other hand, say a developer does not want other projects they are building to end up in the same directory. Should it not further be the case that I use CMAKE_CURRENT_BINARY_DIR OR PROJECT_BINARY_DIR? In the event that just a raw CMAKE_BINARY_DIR is used, without a CACHE, then I have absolutely no way to prevent a sub-project I am building from ending up next to mine.

By using either CMAKE_CURRENT_BINARY_DIR or PROJECT_BINARY_DIR, if a user does not want this library to end up next to the parent project they can simply set the CMAKE_*_OUTPUT_DIRECTORY variables after configuring this one.

Summary

Basically, there don't seem to be any standards for how these variables ought to be used. I'm thrilled at how versatile CMake is, I'm not saying they should be doing any defaults here at all -- that is to be determined by the project. I'm trying to understand what the most appropriate default choice is, that also allows developers to bypass my defaults if they so choose.

svenevs
  • 833
  • 9
  • 24
  • 3
    As you correctly guessed at the beginning, user only wants to select where to **install**. So layout of *build tree* is selected only by project's developer. From the other side, some projects (usually, simple ones), doesn't require installation. But this is done mainly for the projects' simplicity, so such projects rarely allow user to select directories. – Tsyvarev Jun 10 '17 at 07:57
  • This is a good point. I will need to think much more carefully about how I am going about this. The initial thought was to, since my library is (optionally) capable of building all of its dependencies, setup a structure that would enable the user to just `install` my library and my installation would create the necessary `include` directory structure, but just plop all of the libraries in one folder for convenience. I will have to do a lot more research on installation practices! – svenevs Jun 11 '17 at 15:06

1 Answers1

5

I'm with @Tsyvarev. I don't see the user of a CMake enabled project wanting to change the output path of the build artifacts, only the install path.

1. To cache or not to cache?

Just don't set the CMAKE_*_OUTPUT_DIRECTORY variables as cached, because if another CMake project uses yours as a sub-project you would under certain circumstances overwrite your parent project's settings (cached variables are global).

2. Treatment of $<CONFIG> builds

Yes. It's only given when the generator's defaults are not fitting ("Config Name" = "Sub Folder Name").

3. CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR, or PROJECT_BINARY_DIR?

So I would say the save variant would be to first check with an if () statement if someone else has already set the variable and also to use of PROJECT_BINARY_DIR:

if (NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
endif()

Then a user of your project may still set the variables from the outside or a parent project could set it and you have a default if it was not set.

Florian
  • 39,996
  • 9
  • 133
  • 149
  • Very good. I stumbled across a project that also builds python bindings and they had config level settings on windows, but it does seem to generally just work as expected :) Where checking the value is concerned, is there any reason to change behavior if the parent cached it (instead of just set it)? E.g. by checking `get_property(runtimeCached CACHE CMAKE_RUNTIME_OUTPUT_DIRECTORY PROPERTY VALUE SET)`? I think the best practice is just only setting it if it is `NOT` already set. It's not for the users, it's for the developers ;) If I want to move it, please let me! Hehe – svenevs Jun 11 '17 at 15:00
  • @sjm324 I would say normally the outputs of sub-projects - as probably being intermediate build products - are not required to end-up in the final build output destination the user has chosen. But if you want to, this has been also discussed in [set a cmake variable if it is not changed by the user](https://stackoverflow.com/questions/43542381/set-a-cmake-variable-if-it-is-not-changed-by-the-user). You could consider adding a project specific user definable variable like `MY_LIBRARY_OUTPUT_DIRECTORY` that you then can query in your code. – Florian Jun 13 '17 at 19:12
  • I think the second option is the best approach, allowing for output in an alternative location if so desired by the parent. I generally prefix everything like this with an abbreviation of the project name e.g. `PROJNAME_LIBRARY_OUTPUT_DIRECTORY` (not the cmake variable `${PROJECT_NAME}`). But basically, `PROJNAME_LIBRARY_OUTPUT_DIRECTORY` must be cached in order for it to be overriden, however avoids the issues described above where caching `CMAKE_*_OUTPUT_DIRECTORY` can have undesired consequences. Excellent, thank you both for weighing in :) – svenevs Jun 15 '17 at 03:25