cannot change cmake executable output directory on windows - c++

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.

Related

Qt5 make a copy of ini file(QSettings) to build folder using CMake

I'm Qt5 beginner.
I saved two .ini file with QSettings for two different layout of toolbars and dockwidgets.
coolUI.ini and fantacyUI.ini
I move them to my project folder and want to copy them to the build/release folder when building with CMake.
And then I can reset to one of them anytime in my app.
If any information is needed, please tell me.
Assuming your coolUI.ini file is in a project directory/subdirectory that contains a CMakeLists.txt file you may try to use
file(COPY_FILE ${CMAKE_CURRENT_SOURCE_DIR}/coolUI.ini ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/coolUI.ini)
or
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/coolUI.ini DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
or
configure_file(coolUI.ini ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/coolUI.ini COPYONLY)
command from that CMakeLists.txt file to achieve that. Otherwise you need to adapt the input and output paths. CMAKE_RUNTIME_OUTPUT_DIRECTORY is the folder where your executable will be created into.

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.

CMake Error: "add_subdirectory not given a binary directory"

I am trying to integrate Google Test into the subproject of bigger project and I cannot find the solution that would be satisfying for me.
I have two constraints:
the source code of Google Test is already somewhere in the project structure (thus using URL to download it from git repository is not an option)
the source code of Google Test is not a subdirectory of my subproject (and never will)
So when I tried to do something like this:
add_subdirectory( ${GOOGLETEST_PROJECT_LOCATION})
I received:
CMake Error at unit_tests/CMakeLists.txt:10 (add_subdirectory):
add_subdirectory not given a binary directory but the given source
directory "${GOOGLETEST_PROJECT_LOCATION}" is not a subdirectory of
"${UNIT_TEST_DIRECTORY}". When
specifying an out-of-tree source a binary directory must be explicitly
specified.
On the other hand maybe ExternalProject_Add could be a solution but I do not know how shall I use it when I do not want to download sources at all and use sources from specific location in the project.
Project structure looks more or like like this:
3rdparty
|--googletest
...
subproject
|--module1
|--file1.cpp
|--CMakeLists.txt
|--module2
|--file2.cpp
|--CMakeLists.txt
|--include
|--module1
|--file1.h
|--module2
|--file2.h
|--unit_test
|--module1
|--file1test.cpp
|--module2
|--file2test.cpp
|--CMakeLists.txt
|--CMakeLists.txt
CMakeLists.txt
The error message is clear - you should also specify build directory for googletest.
# This will build googletest under build/ subdirectory in the project's build tree
add_subdirectory( ${GOOGLETEST_PROJECT_LOCATION} build)
When you give relative path (as a source directory) to add_subdirectory call, CMake automatically uses the same relative path for the build directory.
But in case of absolute source path (and when this path isn't in your source tree), CMake cannot guess build directory, and you need to provide it explicitly:
See also documentation for add_subdirectory command.
I feel obligated to comment on this because this was the top search result when I was googling this error.
For me, I'm apparently an idiot: I had modified the CMakeLists.txt file in the src directory of my project, but I didn't realize the file was locked and VS Code wasn't actually saving even when I hit Ctrl+S. Check the file tab in VS Code and see if there's a white dot there, indicating the file isn't saved. Hit Ctrl+S and see if you get a pop-up in the lower-right corner prompting you to try again as superuser.
I've still got errors, but they're new errors that make sense for my project.

Why aren't binaries placed in CMAKE_CURRENT_BINARY_DIR?

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}

CMake install (TARGETS in subdirectories)

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.