Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper usage of CMAKE_*_OUTPUT_DIRECTORY

Tags:

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.

like image 879
svenevs Avatar asked Jun 10 '17 05:06

svenevs


1 Answers

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.

like image 148
Florian Avatar answered Oct 11 '22 13:10

Florian