Specifying build directory within CMakeLists file - cmake

Is it possible to specify build directory within CMakeLists file? If yes, how.
My aim is to be able to call "cmake" within top level source directory and have cmake figure out the build directory.

Afaik, with CMake the build directory is always the directory from where you invoke the cmake or ccmake command. So if you want to change the build directory, you have to change directories before running CMake.
To control the location where executables, static and shared libraries are placed once finished, you can modifiy CMAKE_RUNTIME_OUTPUT_DIRECTORY, CMAKE_ARCHIVE_OUTPUT_DIRECTORY, and CMAKE_LIBRARY_OUTPUT_DIRECTORY respectively.

By design, there is not a way to specify that in CMakeLists.txt. It is designed for the user to be able to build the project in whatever directory they want. The typical workflow is:
Check out the project source code.
Go to desired build directory, or the source dir if you plan to do an in-source build.
Run cmake or ccmake to configure the project in that build directory.
Build your project.
All of the directories specified within your CMakeLists.txt should be relative to the ${PROJECT_BINARY_DIR} and ${PROJECT_SOURCE_DIR} variables. In this way, your code becomes buildable across different platforms, which is the goal of CMake.

Related

CMakeLists Equivalent of -B CL Argument [duplicate]

Is it possible to specify build directory within CMakeLists file? If yes, how.
My aim is to be able to call "cmake" within top level source directory and have cmake figure out the build directory.
Afaik, with CMake the build directory is always the directory from where you invoke the cmake or ccmake command. So if you want to change the build directory, you have to change directories before running CMake.
To control the location where executables, static and shared libraries are placed once finished, you can modifiy CMAKE_RUNTIME_OUTPUT_DIRECTORY, CMAKE_ARCHIVE_OUTPUT_DIRECTORY, and CMAKE_LIBRARY_OUTPUT_DIRECTORY respectively.
By design, there is not a way to specify that in CMakeLists.txt. It is designed for the user to be able to build the project in whatever directory they want. The typical workflow is:
Check out the project source code.
Go to desired build directory, or the source dir if you plan to do an in-source build.
Run cmake or ccmake to configure the project in that build directory.
Build your project.
All of the directories specified within your CMakeLists.txt should be relative to the ${PROJECT_BINARY_DIR} and ${PROJECT_SOURCE_DIR} variables. In this way, your code becomes buildable across different platforms, which is the goal of CMake.

Install a target defined in an included directory [duplicate]

Consider the following CMakeLists.txt file:
add_subdirectory(execA)
add_subdirectory(libB)
install(TARGETS execA libB
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
I get the following error:
install TARGETS given target "execA" which does not exist in this
directory
execA and libB have their own CMakeList.txt files and are located under project directory, as well as the build directory I'm running cmake (cmake ..):
project
|------ CMakeList.txt (the one with the code)
|----execA
| \- .cpp, .hpp and CMakelist.txt
|----libB
| \- .cpp, .hpp and CMakelist.txt
|---- lib
|---- bin
\---- build (where I´m commanding: $ cmake ..
How do I fix this error?
According to this bugreport, install(TARGETS) command flow accepts only targets created within the same directory.
So you need either move the add_library() call into the top-level directory, or split install(TARGETS) call into per-target ones, and move each of them into the corresponding subdirectory.
Since CMake 3.13 install(TARGETS) can work even with targets created in other directories.
install(TARGETS) can install targets that were created in other directories. When using such cross-directory install rules, running make install (or similar) from a subdirectory will not guarantee that targets from other directories are up-to-date.
Even though it would help seeing the CMakeLists.txt files contained in the subdirectories, I guess they contain add_executable and/or add_library statements to create your stuff.
Also, because of your example, I guess you are using the same name of your directories for your targets.
That said, you should know that symbols defined in a CMakeLists.txt file in a subdirectory are not visible by default within the context of the CMakeLists.txt file in the parent directory. Because of that, you should rather move your install statements within the CMakeLists.txt files within your subdirectories.
This should solve the problem, if my thoughts were right. Otherwise, I strongly suggest you to post in your question also the content of the other files above mentioned.
Anyway, the error is quite clear.
The file that contains the install statement for the target named X does not contain a target creation statement (add_executable and the others) that gives birth to that target, so it goes on saying that that target does not exist in that directory.
This still seems to be a pain point in CMake 3.11.
In our codebase, we have many targets defined in subdirectories and need to create an assortment of installers with different configurations and (potentially overlapping) combinations of targets.
Here's my solution:
Before calling add_subdirectory in your root CMakeLists.txt file, create a GLOBAL property with the names of the target(s) you want to include in your installer.
Wrap target creation functions (add_executable, etc.) in your own custom functions. Within those functions check if the target is present in the global property, and invoke install accordingly.
That approach allows you to centralize installer configuration.
Also: To support creation of multiple installers, we populate our global list along with other installer properties in separate .cmake files. When we invoke cmake, we pass the name of the installer configuration CMake file as a command-line argument. Our root CMakeLists.txt file simply calls include with that file.

CMake generates project twice

I'm grouping sources in folders by some rules and I want to be able to individually test each group in isolation for faster iteration. To do so I want to CMake to generate one executable for each group. I simplified the project structure to:
root
build
group_1
CMakeLists.txt
group_1_file_1.cpp
group_1_tests
CMakeLists.txt
group_1_file_1_tests.cpp
where group_1/CMakeLists.txt is:
SET(group_1_srcs
${CMAKE_CURRENT_SOURCE_DIR}/group_1_file_1.cpp
)
#Generate standalone application for unit tests when cmake is started with this CMakeLists as root
IF(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
ADD_SUBDIRECTORY("group_1_tests/")
ENDIF()
and group_1/group_1_tests/CMakeLists.txt is
PROJECT(group_1_tests)
SET(group_1_tests_srcs
${CMAKE_CURRENT_SOURCE_DIR}/group_1_file_1_tests.cpp
)
ADD_EXECUTABLE(${PROJECT_NAME} "${group_1_tests_srcs}" "${group_1_srcs}")
Running cmake ../group_1 from root/build/ generates me the project I want, root/build/group_1_tests/group_1_tests.sln, but also root/build/Project.sln with the same files & settings as the previous one.
Can you please explain why this projects gets generate and how may I avoid it?
The answer is in the project() command documentation:
The top-level CMakeLists.txt file for a project must contain a literal, direct call to the project() command ... If no such call exists CMake will implicitly add one to the top that enables the default languages (C and CXX).
So Project is the default project's name. And from that point onward CMake generates a .sln solution for all CMakeLists.txt containing another project() command.
I would recommend you ignore the root solution file (if you don't want it) or restructure your project to have a single project() command call in the root CMakeList.txt (since your sub-level project won't run standalone without the top-level project anyway).
References
CMake Commit: ENH: generate a sln and dsw file for each sub project in a project

Setting CLion build and binary directory

I'm trying to build libwebsockets inside of my project in CLion. During build libwebsockets creates a header file that is required by other files and puts it in PROJECT_BINARY_DIR. CLion builds everything inside a random build directory it creates for the project and the header file ends up in that directory. I've tried:
Setting the websockets_BINARY_DIR variable
Setting the CMAKE_RUNTIME_OUTPUT_DIRECTORY variable
Setting CMAKE_LIBRARY_OUTPUT_DIRECTORY variable
Changing every variable in the CMake cache to point away from CLion's random directory
Changing the build output path setting in CLion's preferences
None of these work, Which leads me to my questions:
Is there a way to tell CLion where to build (not just where to put some of its output buthow to override the random directory it chooses).
If there isn't a way to tell CLion where to build, is there another variable that I should be setting?
I don't know how to set build dir.
Examples of how to set up bin directory with Clion below
set(dir ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${dir}/bin")
or (separate for .exe, .dll, .lib):
set(dir ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${dir}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${dir}/lib")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${dir}/bin")
Also I added link about how to set up build directory:
https://stackoverflow.com/a/28200869/3001953
But it soesn't work in my case (Clion 1.1).
You may also have a look at the Clion built-in path variables: https://www.jetbrains.com/help/clion/2019.2/absolute-path-variables.html

installing a cmake target in two different folders

My source tree includes several executables and shared libraries (dlls). I would like to change my cmakelists.txt files so that executables are installed in multiple destination folders on the installer's sytem.
Source Tree
Editor
Editor.cpp
CMakeLists.txt
Game
Game.cpp
CMakeLists.txt
SharedLib
SharedLib.cpp
CMakeLists.txt
Desired install directory structure
Editor/
MyEditor.exe
MySharedLib.dll
Game/
MyGame.exe
MySharedLib.dll
Currently I use a install(TARGET MySharedLib RUNTIME DESTINATION Editor) but I also need to install MySharedLib for a second time and into Game directory.
How can I achieve this?
It is possible to specify multiple install locations for a cmake target by calling install() multiple times (http://www.cmake.org/cmake/help/v3.2/command/install.html#installing-targets).
However this call can only take place in the cmakelists.txt file of the targets directory.