Where to put the binary in CMake? - cmake

in my project, all source code resides in a folder named "src". There's a CMakeLists.txt file in my projects root (above "src"), but it merely declares the project and includes the "src" subdirectory. The CMakeLists.txt file under src does all the work, including "add_binary".
(Is that a common way of doing it, or should I put all the intelligence in the CMakeLists.txt file at the root level?)
If I build the project now, my binary is placed into the src folder, but this doesn't make a lot of sense, I'd rather have it in the root folder or a dedicated "bin" folder.
How do you do this?

If you want to put all your executable files in a subdirectory called "bin", then you can use the following line in the top CMakeLists.txt file:
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
Just remove /bin and executables will be created in the root directory. A similar variable exists for libraries: CMAKE_LIBRARY_OUTPUT_DIRECTORY.
PS. Adding per-directory logic is fine. It seems to be the common way to do things and keeps things nicely organized.

Related

CMake generation requiring generated files

I'm building a project using CMake in multiple subdirectories. There is a parent directory containing a parent CMakeLists file, and each subdirectory contains its own CMakeLists file. As such, I'm using the add_subdirectory command to run the subdirectories.
My issue is that one of the subdirectories generates code that another subdirectory needs in order to build. Specifically, it's Google Protocol Buffers. The CMakeLists file in that subdirectory will generate the pb.cc and pb.h files if run independently, but until I do so, I cannot generate the cache of the parent CMake file as it complains it's missing those source files.
Directory structure is as follows:
/
--CMakeLists.txt
--protobuf/
----CMakeLists.txt
----src/
--main/
----CMakeLists.txt
----src/
Where the main subdirectory requires files generated by the protobuf subdirectory.
Is there a way I can have the parent CMakeLists file build the subdirectory as part of its generation step? Or somehow mark the protobuf files as required, but missing, so the generation does not fail?
You can try running this particular cmake file as execute_process before including the main file. But this goes against the designed cmake usage.
The correct answer would be to make your generation step a part of build process. If you can post a minimal, reproducible example of your problem I could give you concrete ways to solve your problem directly instead of making your workaround work.

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.

Avoid repeating the directory name for multiple file inclusions

I have a CMakeLists.txt file for a library. It's pretty basic:
set(LIB_FILES source/first.cpp)
add_library(first ${LIB_FILES})
I put the files in a list because I will eventually be adding more source files to the library. The problem is that all of the files will be in the source directory. And I don't want to constantly have to repeat that.
I also don't want to use the GLOB pattern matching solution, because I want to have to edit the CMakeLists.txt file when I add a new file. That way, my build will re-build the build solution, and new files will correctly appear (as I understand it. I'm still new with CMake).
I tried adding a CMakeLists.txt file into the source directory itself, just to build the LIB_FILES list. That didn't work out very well. Variables in CMake are file scoped. And even when I broke scoping (with PARENT_SCOPE), I still had to prefix each file with the directory. So that gained nothing.
I don't want to put the actual library definition in the source directory, as that will generate all the build files in the source directory. And I don't want that. Also, I will need to include headers that aren't in or under the source directory.
My directory structure looks like this:
libroot (where the project build files should go)
\-source (where the source code is)
\-include (where the headers that the user of the library includes go)
So how do I tell CMake that all of the source files come from the source directory, so that I don't have to constantly spell it out?
You could move the add_library call to your source/CMakeLists.txt also:
set(LIB_FILES first.cpp)
add_library(first ${LIB_FILES})
Then just use add_subdirectory in your top-level CMakeLists.txt:
add_subdirectory(source)
you could use a simple macro for that
macro(AddSrc dst_var basepath_var)
foreach(file ${ARGN})
list(APPEND ${dst_var} ${basepath_var}/${file})
endforeach()
endmacro()
set(MY_SRCFILES "")
AddSrc(MY_SRCFILES path/to/source
foo.cpp
bar.cpp
whatever.cpp
)

CMake: How to get subdirectories to use source files from the root directory

I have this variable set in the root CMakeLists.txt
set(${LIBNAME}_srcs
File1.cpp
File2.cpp
File3.cpp
File4.cpp
File5.cpp
)
add_subdirectory(A)
and I want to add the variable as a source for the executable in the subdirectory A
add_executable(${TEST}}
What is the cleanest way to do this? without having to create a new variable with ../ on all the source files? Or is there a macro I can use?
You can insert the absolute path to each of the values in ${LIBNAME}_srcs by doing something like:
foreach(${LIBNAME}_src ${${LIBNAME}_srcs})
list(APPEND abs_${LIBNAME}_srcs ${CMAKE_SOURCE_DIR}/${${LIBNAME}_src})
endforeach()
add_executable(${TEST} ${abs_${LIBNAME}_srcs})
Jumping to conclusions here, it looks like what you're doing may be a bit unusual.
Normally the add_executable call would be made in the same place where the list of source files is gathered - usually in the same directory.
Going by the fact that you've named your sources variable ${LIBNAME}_srcs, I'd guess that you're already creating a library from these sources. If so, it'd be better to just link that library in your test subdirectory rather than recompiling all the library's sources into the executable.
Something like:
add_executable(${TEST} test_main.cpp)
target_link_libraries(${TEST} ${LIBNAME})
When I add sources, I do something like this:
set(${LIBNAME}_srcs
${SRC}/File1.cpp
${SRC}/File2.cpp
${SRC}/File3.cpp
${SRC}/File4.cpp
${SRC}/File5.cpp
)
Where ${SRC} is the absolute path to the source directory found using ${CMAKE_SOURCE_DIR}.
Then, you can simply use add_executable(${TEST} ${LIBNAME}_srcs) in your subdirectory. CMake will automatically import the scope of parent directories into child directories.

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.