Why aren't binaries placed in CMAKE_CURRENT_BINARY_DIR? - c++

It is my understanding that CMAKE_CURRENT_BINARY_DIR should point to the directory where binaries for the current CMakeLists.txt file will be placed. However, this doesn't seem to be the case.
Consider this file structure:
CMakeTest
+- CMakeLists.txt
+- main.cpp
CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
add_executable(CMakeTest main.cpp)
message(STATUS "CMAKE_CURRENT_BINARY_DIR = ${CMAKE_CURRENT_BINARY_DIR}")
main.cpp
#include <iostream>
int main() {
std::cout << "Hello, World!";
return 0;
}
On the (Windows) command line, I run the following commands:
md build
cd build
cmake .. -G "Visual Studio 14 2015"
cmake --build .
The first cmake command prints (among other things) the line
CMAKE_CURRENT_BINARY_DIR = X:/dev/projects/CMakeTest/build
So I'd expect the resulting binary file CMakeTest.exe to end up there. Really, however, it is placed in X:/dev/projects/CMakeTest/build/Debug.
Why isn't the binary file placed into CMAKE_CURRENT_BINARY_DIR, but in a sub-directory? And is there any CMake variable that tells me what that subdirectory is?
Edit:
I'm not trying to change the directory where binaries are placed. I'm trying to determine it. The reason is this:
During build, a number of additional resource files are created in the same directory as the executable file. (This part works.) I'd like to use the install(FILES, ...) command to then add these files to the resulting package. So I need to pass the actual path where the binaries are placed to install(FILES, ...).

Variable CMAKE_CURRENT_BINARY_DIR denotes "binary directory currently being processed" by CMake. Usually, this directory and its subdirectories contains build artifacts, like executables, libraries or other generated files.
If you want to control location of executable being built, you need to set variable CMAKE_RUNTIME_OUTPUT_DIRECTORY.
Note, that multiconfiguration build tools, like Visual Studio, for each specific configuration will create subdirectory (named as configuration itself) under CMAKE_RUNTIME_OUTPUT_DIRECTORY. Otherwise, executables created for different configurations would overwrite themselves.
For precise control of per-configuration directory used for built executables, use variable CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>. (Instead of <CONFIG> name of specific configuration should be inserted, so CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG variable will affect Debug builds).
For just determine directory with executable, use $<TARGET_FILE_DIR:tgt> generator expression (instead of tgt a name of the target created the executable should be used).
Note, that generator expressions can be used only in specific places. E.g., list of files for install(FILES) command can use generator expression, but message() command cannot.

Yes, the executables are often stored at a level below the CMAKE_CURRENT_BINARY_DIR, based on the build type. You can navigate to this directory directly by using ${CMAKE_BUILD_TYPE} (which is typically has value of Debug or Release) by building a full path like:
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}

Related

why the relative path is different when I use Cmake build and VS 2019 build?

I'm new in Cmake. And I try to use Cmake to construct my project.
In my project, I need to load some resources in runtime. for instance:
string inFileName = "../Resources/resource.txt";
// string inFileName = "../../Resources/resource.txt";
ifstream ifs;
ifs.open(inFileName.c_str());
if (ifs) {
....
}
But when I use the command line cmake ../ and cmake --build . --config Release in project/build. my file path should be relative to ${PROJEDCT_BINARY}, i.e. inFileName = "../resources/resource.txt".
But when I use cmake ../ and open the sln file with VS2019 then right-click to build and run, my file path should be relative to the executable, i.e. inFileName = "../../resources/resource.txt".
I don't know why this happened, and I search through Internet, It seems no one else encounters this stupid question...
Below is my file structure.
|--3rdParty
|----CmakeLists.txt
|--include
|----header.h
|--source
|----source.cpp
|----CmakeLists.txt
|--resources
|----resource.txt
|--CmakeLists
and my root CmakeLists.txt
cmake_minimum_required(VERSION 3.12)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(OBMI VERSION 0.1.0.0 LANGUAGES C CXX CUDA)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
add_subdirectory(3rdParty)
add_subdirectory(source)
source/CmakeLists.txt
add_executable(mSI)
target_sources(mSI PRIVATE
${PROJECT_SOURCE_DIR}/include/header.h
# source
source.cpp
)
target_include_directories(multiSpectrumImaging
PRIVATE
${PROJECT_SOURCE_DIR})
target_link_libraries(mSI
PRIVATE
...
)
When using relative paths to load files, the resolution of the final filename depends on the current working directory. The relative path is appended to that working directory. That current working directory is not necessarily the same as the path of your application; it will be the path of the surrounding environment from which the application is started (or can be set specifically for a debug environment in most IDE's).
You don't specify exactly how you run your program when you run it not from the IDE - just by double-clicking the executable maybe? You also don't tell us where the executable is built in relation to your sources?
Specifically for running from Visual Studio, you can set the working directory in the "Debugging" section of the Project Properties.
For a more flexible solution, what I typically do is to determine the path of your executable, and then appending the relative path to load resources to that.
Basically, the full executable path is stored in argv[0] (if you have a int main(int argc, char** argv) {...}, i.e., the first element of the second argument to your main function). For more information on this, see for example the answers to this other question.
By generating an MSVS solution file you (CMake) create a working environment for MSVS where the solution (and projects) is generated. So everything relative there would be relative to those files generated and as far as MSVS is concerned, that directory is the center of the world. That's why you should strive to use absolute and not relative paths.
To achieve that CMake has a bunch of variables and PROJECT_SOURCE_DIR, which you use, is one of them. But there is one which seems to suite your case better case, though: CMAKE_SOURCE_DIR.
So whenever you need to use your resources, use the following path in your CMake script: "${CMAKE_SOURCE_DIR}/resources/resources.txt"
If you need your resources to load in runtime then it goes beyond CMake and its capabilities. You should put these resources relative to your resulting binary because what place they have in the project doesn't matter anymore. CMake helps with it by providing install and file(COPY ...). Where the former is mostly used during the packaging of your application and the latter might be used during development to ease the burden.
For example, you can have the following in your project (source/CmakeLists.txt) CMake file:
file(COPY "${CMAKE_SOURCE_DIR}/resources" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
Which should place the resources folder where your binary gets created.

CMake retrieve output path

In my Application the user can click on a "Build" button. This will invoke a file dialogue where the user selects the folder with the CmakeCache. After that I'll invoke the cmake --build command with system(command) and the executeable will be built.
Now I'd like to know the path where the executeable was built. I need to copy files into that path.
I know that the file located at /CMakeCacheFolder/projectname/projectname.dir/Release/projectname.log contains the compiler log with the output path in the last line. But is there some other way?
Output directory of the executable/library target tgt can be obtained with generator expression
$<TARGET_FILE_DIR:tgt>
Because this is a generator expression, it can be used only in limited cases. (CMake documents every command and parameter, for which a generator expression can be used).
If you know, that output directory for the target is set via assigning CMAKE_RUNTIME_OUTPUT_DIRECTORY variable, then you may read either this variable or the target's property RUNTIME_OUTPUT_DIRECTORY. Unlike to the generator expressions, the variable's and the property's values can be used everywhere.
But note, that in case of multi-configuration generators (like Visual Studio), configuration name is appended to the variable's (or property's) value for obtain real output directory.
Not a full answer but too much for a comment:
You can define the output directories for executables, shared objects, and libraries for a project as follows:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
And as you determine where to build you now have a common output directory under a well known path.
The directories could also be given on a configuration basis (Debug/Release/RelWithDebInfo/...) as follows
CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG
CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE
CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO
Hope that helps you further.

Compile a single file under CMake project?

I'm developing a C++ project which is going to be enclosed on a bigger one.
I've seen that on the bigger project (is a Qt application and it's being generated from qmake) I am able to compile a single file from the linux command line, just entering the relative path to the specific file as an argument to make.
On the other hand, I'm using CMake for my own project. When I modify some code for a compilation unit and I have to modify its header file, I have to wait a long time to compile its dependencies and then its own source file. But there are some situations in which I would prefer to check whether the source code in the *.cc file is compilable without errors.
Is there a way to generate a Makefile from CMake the way qmake does this? Switching to qmake is not an option anymore.
You do not have to add extra custom targets to your CMake scripts, as the Makefiles generated by CMake already contain .o targets for each .cc file. E.g. if you have a source file called mySourceFile.cc, there will be a Makefile in your build directory that defines a target called <Some Path>/mySourceFile.cc.o. If you cd into your build directory, you can use grep or ack-grep to locate the Makefile that defines this target, then cd into that Makefile's directory and build it.
E.g. suppose the command ack-grep mySourceFile.cc.o prints something like:
foo/bar/Makefile
119:x/y/z/mySourceFile.o: x/y/z/mySourceFile.cc.o
123:x/y/z/mySourceFile.cc.o:
124: # recipe for building target
Then you can build mySourceFile.cc.o by doing:
cd foo/bar && make x/y/z/mySourceFile.cc.o
CMake doesn't have a generic built-in way of doing this (it's an open issue), but if you're using the Ninja generator, you can can use a special Ninja syntax for building just the direct outputs of a given source file. For example, to compile just foo.o you would use:
ninja /path/to/foo.cpp^
Not out-of-the box. CMake does not expose those "internal" makefile rules in the main makefile.
You can do this only if you consider what kind of file structure CMake uses internally. You can e.g. for compiling a single .obj files using CMake generated makefiles call
make -f CMakeFiles/myProg.dir/build.make CMakeFiles/myProg.dir/main.cc.obj
when you have something like
cmake_minimum_required(VERSION 3.1)
project(myProg CXX)
file(WRITE "main.cc" "int main()\n{\nreturn 0;\n}")
add_executable(myProg main.cc)
To build src/foo.cpp alone:
cmake --build . --target src/foo.cpp.o
No, CMake does not offer built-in support to compile single files.
You have to add a target for each object file, maybe by a function iterating over all files of a directory.
Others have suggested ways to find the target name (ending in .cpp.o) from the .cpp filename, but if you already know the name of a target that will trigger compilation of the .cpp file and you're using ninja this suggestion should be easier.
First build the target:
ninja TriggersCppCompilationLib
Assuming your file was changed or was not yet built, ninja will print the full target name. When you see the name come up, hit enter so it is not overwritten. Then simply copy the name from the terminal (e.g. using tmux copy mode).

cannot change cmake executable output directory on windows

I have a project that builds on both Linux and Windows.
In that, I have in a subfolder somedir/modules/MyModule a CMakeLists.txt which should add some test executables. cmake wants to put them in some subdirectory binary folder, but I want to place them in the common binary folder under ${CMAKE_BINARY_DIR}/x64
So what I'm doing is this (in the CMakeLists.txt in the somedir/modules/MyModules directory):
ADD_EXECUTABLE(MyTest MyTest.cpp)
set_target_properties(MyTest PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x64")
TARGET_LINK_LIBRARIES(MyTest SomeLibraries...)
ADD_TEST(MyTest ${CMAKE_BINARY_DIR}/x64/MyTest)
Under Linux this works nicely, but under Windows I simply cannot get it to build into the ${CMAKE_BINARY_DIR}/x64 folder. I've checked via MESSAGE, the ${CMAKE_BINARY_DIR}/x64 does point to the right folder. I also tried changing the CMAKE_RUNTIME_OUTPUT_DIRECTORY (or even the per-target variables, e.g. CMAKE_MyTest_OUTPUT_DIRECTORY, MyTest_OUTPUT_DIRECTORY_Release, MyTest_OUTPUT_DIRECTORY_Debug, as mentioned here: https://stackoverflow.com/a/25328001/671366). Tested both before or after ADD_EXECUTABLE, doesn't change anything. The output directory stays fixed on somedir/modules/x64/.
I'm out of ideas what I need to do, or even where the output directory it insists on using is coming from. Any ideas? At which point in time is the output directory decided in cmake? How does this relate to subdirectories? The executables specified in the parent folder CMakeLists.txt files get built in the desired directory, but if that is by mere chance I can't really say.
Config-specific property RUNTIME_OUTPUT_DIRECTORY_<CONFIG> has priority over common one RUNTIME_OUTPUT_DIRECTORY. Both types of properties are initialized from corresponded CMAKE_* variable(if it is set) when executable target is created.
So, having e.g CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG config-specific variable being set makes this variable to be used for Debug configuration even if RUNTIME_OUTPUT_DIRECTORY property is explicitely set. The only way to redefine output directory in that case is to set RUNTIME_OUTPUT_DIRECTORY_DEBUG config-specific property.

clion run cmake on each build

I am not sure if its possible to do this with clion, I was testing out the program and enjoy using it to write c code because the ctags and etags support is really nice.
I am copying some files over from the cmake source tree to the bin location on each build. While using clion if I update some of the files that I am copying the results aren't updated within clion.
If I instead go back to the terminal and just run the typical cmake steps
cmake ../ && make && bin/./program
that copies the updated files and I am able to see my results.
This is the CMake command that I am using in my build.
FILE(COPY ${CMAKE_CURRENT_SOURCE_DIR}/resources/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/bin/resources/)
I might be able to restructure the cmake command to make it copy every time or it might just be a clion issue. I am unsure and would like to be able to take care of this all from within clion, instead of going back to the terminal to run the cmake command for updates to take effect.
If you want CMake to make some action whenever some file is changed, you should create a rule using add_custom_command and pass file via DEPENDS argument. Note, that only file-level dependencies are supported by CMake, for make dependency on directory you need to list all files in it.
# Collect list of files within directory.
FILES(GLOB files_list RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/resources/
"${CMAKE_CURRENT_SOURCE_DIR}/resources/*")
# This will contain full paths to files in binary directory.
set(binary_files_list)
foreach(file ${files_list})
set(source_file ${CMAKE_CURRENT_SOURCE_DIR}/resources/${file})
set(binary_file ${CMAKE_CURRENT_BINARY_DIR}/bin/resources/${file})
add_custom_command(OUTPUT ${binary_file}
COMMAND cmake -E ${source_file} ${binary_file}
DEPENDS ${source_file})
list(APPEND binary_files_list ${binary_file})
endforeach()
add_custom_target(resources DEPENDS ${binary_files_list})
Note, that in case of adding/removing files you should to run cmake explicitely. That's why hardcoded files list is preferred to GLOBing.