cmake subdirectories install - cmake

I would like to set up a new project using CMake.
My working dir is the following :
CMakeLists.txt
include
- file1.h
src
- file1.cpp
- CMakeLists.txt
tests
- test1.cpp
- CMakeLists.txt
The main CMakeList.txt is the following:
cmake_minimum_required(VERSION 2.8)
project(bench CXX)
include_directories(include)
subdirs(src tests)
The src CMakeList.txt is :
add_library(foo SHARED file1.cpp)
install(TARGETS foo DESTINATION lib)
And the tests CMakeList.txt is:
add_executable(test1 test1.cpp)
target_link_libraries(test1 foo)
install(TARGETS test1 DESTINATION bin)
I would expect the files to be located in
<build_dir>/bin/test1
<build_dir>/lib/libfoo.so
But instead they are organized like this :
<build_dir>/src/test1
<build_dir>/tests/libfoo.so
What am I doing wrong ?
Thanks in advance,

You are giving instructions for the install step/build target, which is independent from the build tree under <binary_dir>.
Set CMAKE_INSTALL_PREFIX to a folder of your choice and run make install (assuming make build system here) after your build. The you will find CMAKE_INSTALL_PREFIX/lib/libfoo.so and CMAKE_INSTALL_PREFIX/bin/test1 as you told cmake. The DESTINATION path is always relative to CMAKE_INSTALL_PREFIX (unless you specify an absolute path, of course).
The compiled libs and binaries within the build tree (i.e. <build_dir>) will always reflect the source tree structure with respect to location; this cannot be changed and is not the intended way of use.
Generally there are three different "things": Source/Build/Install trees. The build tree mirrors the source tree structure and contains cmake-generated extra files and objects. The install "tree" is a setting of your choice, where CMAKE_INSTALL_PREFIX is the root directory under which libraries, archives and binaries are placed. You can control the behaviour completely (what you already intend to do!), although there are reasonable default settings.

Related

In CMake, how would one run a custom command only if any subdirectory needed to be rebuild

I have a CMake-based project, and I need to run a command after build, if anything changed, including in any subprojects.
Simplified structure
project_root/
CMakeLists.txt (project root)
executable_1/
CMakeLists.txt (project tool1)
library_1/
CMakeLists.txt (project lib1)
executable_2/
CMakeLists.txt (project tool2)
library_2/
CMakeLists.txt (project lib2)
library_3/
CMakeLists.txt (project lib3)
The project root CMakeLists.txt looks like
cmake_minimum_required(VERSION 3.17)
add_subdirectory(tool1)
add_subdirectory(tool2)
add_subdirectory(lib3)
project(root C)
add_custom_target(root ALL
COMMENT
"root target"
DEPENDS
${DEPLOY_PATH}/deploy.tar.xz
)
add_custom_command(
OUTPUT
${DEPLOY_PATH}/deploy.tar.xz
COMMAND
tar cJf ${DEPLOY_PATH}/deploy.tar.xz *
COMMENT
"taring"
DEPENDS
root
)
The tool CMakeLists.txt look about like
cmake_minimum_required(VERSION 3.17)
add_subdirectory(lib1)
project(tool1 C)
add_executable(tool1
src/tool1.c
)
target_include_directories(tool1
PRIVATE
./
)
target_link_libraries(tool1
PRIVATE
lib1
lib3
)
install(TARGETS tool1 DESTINATION ${DEPLOY_PATH})
with the lib's CMakeLists.txt files omitting the install line and providing appropriate public include directories, etc.
I can get the behavior I want if I explicitly list every single subproject in the DEPENDS line of the custom target for "root", but that's tedious and error-prone. In the real project there are dozens of sub-libraries and executables.
I can also easily just re-build the archive every time, but that's slow.
How do I rebuild the archive if (and only if) any of the sub-projects of the root project or their descendants has changed?
List the actual dependencies of the tool.
file(GLOB_RECURSE srcs *) # I hope that's correct
add_custom_command(
OUTPUT
${DEPLOY_PATH}/deploy.tar.xz
COMMAND
# * generally is invalid, * depends on shell filename expansion
tar cJf ${DEPLOY_PATH}/deploy.tar.xz *
COMMENT "taring"
DEPENDS ${srcs}
)
But that's wrong anyway - cmake is meant to be run once and it scans your tree once. If you add a new file, you'll have to reconfigure cmake. Rather consider building the archive only when you actually need it - when deploying.

CMake copy dll transitively

Basically I want CMake to copy dependency's dll to the same directory of the executable. Suppose I have the following directory structure:
my-project/
CMakeLists.txt
lib/
CMakeLists.txt
... # Some source files
app/
CMakeLists.txt
... # Some source files
The library lib depends on some third party dll, say foo.dll. The executable in app, say app.exe, depends on lib.
I've written a FindFOO.cmake to make the third party library foo.dll an imported target named foo.
Now when I compile app, in order to run the executable, foo.dll is required to be in the same directory as app.exe. How can this be achieved automatically with cmake? And what if I want to use CPack to package the application into an installer?
CMAKE_RUNTIME_OUTPUT_DIRECTORY is your friend.
If this variable is created before creating some target, if the target is RUNTIME, it will define where the output of the target will be placed.
In your case, it can be used to force foo.dll and app.exe to be in the same folder. Your root CMakeLists.txt should look like this:
cmake_minimum_required(VERSION 3.15)
project(foo_and_app)
# app.exe and foo.dll will be in bin subfolder of build dir
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_subdirectory(lib)
add_subdirectory(app)
#not connected to placement, but only to package creation
include(CPack)
It should be noted that this variable is used to initialize the properties of the targets added, meaning that everything may also be achieved by directly manipulating appropriate target properties.
Regarding packaging, what you ask is possible, regardless of the placement of runtime targets, by using install cmake statement. In lib/CMakeLists.txt you should add something like this:
# suppose that the target named `foo`,
# i.e. it is added by add_library(foo SHARED .....)
install(TARGETS foo
RUNTIME DESTINATION bin
)
same should be done for app/CMakeLists.txt:
# suppose that the target named `app`,
# i.e. it is added by add_executable(app .....)
install(TARGETS app
RUNTIME DESTINATION bin
)
If you have these install statements, the final destination will be bin folder within the chosen install folder.
In the end, here are the links for CMake documentation describing:
CMAKE_RUNTIME_OUTPUT_DIRECTORY variable
RUNTIME cmake targets
install(TARGETS ...)

Confusion on how CMake places binaries

I've recently began experimenting with CMake, and have written a simple Hello, World program in C++.
Here is my directory structure:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
build/
The top-level CMakeLists.txt reads as follows:
#Require at least CMake version 2.8
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
#set up the project name, version and language to compile in
project(HelloWorld)
#tell CMake that we have some source files located in the src directory
add_subdirectory(src)
And the CMakeLists.txt in /src reads:
add_executable(helloworld
main.cpp)
install(TARGETS helloworld
RUNTIME DESTINATION ../build)
Now, I would expect that these two scripts would cause the makefile to create the helloworld binary in the /build directory, but after running make, it creates the helloworld binary in /build/src.
If I move the add_executable and install function calls into the top-level CMakeLists.txt, then the helloworld binary is placed in /build, not /build/src.
So, as I understand, it places the build in the folder relative to where CMake was invoked. Why does it appear as though install is doing nothing, then?
Additionally, what if I have multiple complex subdirectories?
How should I write out my CMakeLists.txt while avoiding file(GLOB ...)?
For example;
CMakeLists.txt
/build
/src
/class_A
a.hpp
a.cpp
/class_B
b.hpp
b.cpp
/class_CB
cb.hpp
cb.cpp
/class_D
d.hpp
d.cpp
Would I just have a giant list of .cpp files, all with relative paths to each cpp file, and pass that list into the add_executable(executable ${SOURCE_FILES})? Or is there an easier way with using multiple CMakeLists.txt?
You misinterpret the install command. It is used to install your files, for example with make install.
When you configure your project, CMake will mimic the structure of your project. This means all folders are created in the same structure and the binaries appear in the according build directories.
Either place your targets in the main directory, which I would consider bad stile. Better live with build/src or give it a more meaningful name.

CMake and dependencies

I have the following directory structure and library dependencies:
./lib-a
./lib-b (depending on lib-a)
Each directory contains a CMakeLists.txt file for generating its own library.
I am using an out-of-source building policy.
In order to say that lib-b depends on lib-a, I have put the command add_subdirectory(../lib-a lib-a) in ./lib-b/CMakeLists.txt, according to what is taught by the official CMake tutorial. This way I obtain that a subdirectory lib-a is created in ./lib-b/build dir.
This is not the behaviour I desire. What I would like to obtain is CMake making reference to lib-a in generating lib-b and, if lib-a has not been already generated, CMake should generate it inside ./lib-a/build by using the CMakeLists.txt of lib-a (in a behaviour similar to the one of the make tool when dealing with dependencies).
I would also like to add that I am not using a root CMakeLists.txt in my example, but what I would like to have is the lib-b/CMakeLists.txt declaring the dependency on lib-a, thus making lib-a to be compiled, if not already, by using its own lib-a/CMakeLists.txt.
Here is the dirs structure and their contents:
lib-a/
CMakeLists.txt (for compiling lib-a)
src/
test.cpp
include/
test.hpp
lib-b/
main.cpp
CMakeLists.txt (for compiling lib-b; here is the point where I would like to make reference to lib-a, that I need for the generation of lib-b)
lib-b/main.cpp contains also an include of test.hpp of lib-a, because it is using a function of lib-a. This should be taken into consideration in the specification of lib-b/CMakeLists.txt.
What should the content of the two lib-a/CMakeLists.txt and lib-b/CMakeLists.txt files be?
I think you misunderstand the tutorial. The thing that links the libraries together is target_link_library(lib_b lib_a). If the name of the dependency is a library that is part of the build, CMake will magically make the dependencies work. It has nothing to do with subdirectories. In fact, if I have the following directory structure:
./
./a.hpp
./a.cpp
./b.hpp
./b.cpp
./CMakeLists.txt
The following will set the dependencies just fine:
PROJECT(lib_a)
ADD_LIBRARY(lib_a a.hpp a.cpp)
PROJECT(lib_b)
ADD_LIBRARY(lib_b b.hpp b.cpp)
TARGET_LINK_LIBRARIES(lib_b lib_a)
This will work across subdirectory projects as well:
./
./CMakeLists.txt
./lib_a/CMakeLists.txt
./lib_a/a.hpp
./lib_a/a.cpp
./lib_b/CMakeLists.txt
./lib_b/b.hpp
./lib_b/b.cpp
And the list files:
# ./CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
ADD_SUBDIRECTORY(lib_a)
ADD_SUBDIRECTORY(lib_b)
# ./lib_a/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(lib_a)
ADD_LIBRARY(lib_a a.hpp a.cpp)
# ./lib_b/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(lib_b)
INCLUDE_DIRECTORIES(${lib_a_SOURCE_DIR})
ADD_LIBRARY(lib_b b.hpp b.cpp)
TARGET_LINK_LIBRARIES(lib_b lib_a)

Changing cmake directories

I'm writing a cmake file for a project which has the following structure
project/ (root)
libraries/ (contains (precompiled) libraries
src/
code/ (contains a set of fortran files)
My CMakeLists.txt file is currently in project/ and effectively is just
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (sc1 sc1.f90)
target_link_libraries(sc1 ${PROJ_LIBRARY})
This creates my binary in the same folder as the source code, when I actually want it in the level above (i.e. in the src folder - this structure will be changed so we have a bin folder eventually), but haven't worked out how to do it.
Some answers on SO say you have to have a CMakeLists.txt file in every folder - is this correct? Is it possible to set an environment variable or use a CMake variable (e.g. http://cmake.org/cmake/help/v2.8.8/cmake.html#command:set). It's also not very clear from some answers whether the solutions they have posted are C++ specific (as that is what language CMake most often seems to be used for).
Edit
I found out that I can change it to the behaviour I want by modifying it slightly:
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (src/sc1 ${projsrc}/sc1.f90)
target_link_libraries(src/sc1 ${PROJ_LIBRARY})
However, this doesn't explain why my behaviour is different to how it should be, according to arrowdodger below. I'm also still trying to work out how to display the values of environment variables; I've tried the following with no luck:
message(${RUNTIME_OUTPUT_DIRECTORY})
message($ENV{RUNTIME_OUTPUT_DIRECTORY})
message(${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
message($ENV{CMAKE_RUNTIME_OUTPUT_DIRECTORY})
By default, binaries will appear in respective subdirectory of your build dir. By respective i mean the directory that contains CMakeLists.txt with add_executable() call.
For example, if you have following CMakeLists.txt
add_executable(tgt1 src1.f90)
add_executable(tgt2 subdir/src2.f90)
in the root folder, you will get both binaries in ${CMAKE_BINARY_DIR}. So if you wish tgt2 to be in ${CMAKE_BINARY_DIR}/subdir, you need to add CMakeLists.txt there and call add_executable(tgt2 src2.f90) from there.
You can change this behavior:
CMAKE_LIBRARY_OUTPUT_DIRECTORY, CMAKE_RUNTIME_OUTPUT_DIRECTORY and others.
You can also set respective target properties.