Difference between CMAKE_CURRENT_SOURCE_DIR & CMAKE_SOURCE_DIR variables? - build

as I understood, these variables are used in case project consist of sub directories e.g. every sub directory further have CMakeLists.txt files.
CMAKE_CURRENT_SOURCE_DIR
refers to the path of source director under process ?
and
CMAKE_SOURCE_DIR
refers to top most source directory ?
I am not sure about it.

CMAKE_SOURCE_DIR is where cmake was originally invoked, and CMAKE_CURRENT_SOURCE_DIR is where cmake is currently working. For instance, if you use add_subdirectory command to include a dependency to your project, the dependency will have its own CMAKE_CURRENT_SOURCE_DIR but CMAKE_SOURCE_DIR will remain the same.
Expanding on Some programmer dude comment, imagine you have the following three CMakeFiles on different directories on your project
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
message("root dir CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}")
message("root dir CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}")
add_subdirectory(sub1)
add_subdirectory(sub2)
sub1/CMakeLists.txt
message("sub1 dir CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}")
message("sub1 dir CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}")
sub2/CMakeLists.txt
message("sub2 dir CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}")
message("sub2 dir CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}")
Running cmake . on the root directory gives me this output
root dir CMAKE_SOURCE_DIR = /Users/henrique/cmake_tests
root dir CMAKE_CURRENT_SOURCE_DIR = /Users/henrique/cmake_tests
sub1 dir CMAKE_SOURCE_DIR = /Users/henrique/cmake_tests
sub1 dir CMAKE_CURRENT_SOURCE_DIR = /Users/henrique/cmake_tests/sub1
sub2 dir CMAKE_SOURCE_DIR = /Users/henrique/cmake_tests
sub2 dir CMAKE_CURRENT_SOURCE_DIR = /Users/henrique/cmake_tests/sub2
Now if I run cmake . on the sub1 directory I get the same value for both variables:
sub1 dir CMAKE_SOURCE_DIR = /Users/henrique/cmake_tests/sub1
sub1 dir CMAKE_CURRENT_SOURCE_DIR = /Users/henrique/cmake_tests/sub1

Related

extract header file exported Target (Shared Library) using CMake

Background
I am trying to use the export/import feature of CMake.
My project structure as like as follows
cmake_export_import
|-- child_project
| |-- CMakeLists.txt
| |-- include
| | `-- child.h
| `-- src
| |-- child.cpp
| `-- main.cpp
`-- parent_project
|-- CMakeLists.txt
|-- include
| `-- parent.h
`-- src
|-- main.cpp
`-- parent.cpp
I want to use the property of parent_project into child_project
I will not use add_subdirectory in child_project to add the parent project Also I will not do make install during building parent_project. This is my limitation or requirements, whatever you say.
Approach
Building parent proj
I have followed this to achieve this.
CMakeLists.txt from parent_project
cmake_minimum_required(VERSION 3.10)
project(parent)
# Set the main target name to the project name
set(MAIN_TARGET_NAME ${PROJECT_NAME})
# executable file path
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../bin)
# Create the C++ shared library
add_library(${MAIN_TARGET_NAME}_lib SHARED ${${PROJECT_NAME}_SOURCE_DIR}/src/parent.cpp)
# Targetting header files for the target ${MAIN_TARGET_NAME}_lib
target_include_directories(${MAIN_TARGET_NAME}_lib PUBLIC ${PROJECT_SOURCE_DIR}/include)
add_executable(${MAIN_TARGET_NAME}_executable ${${PROJECT_NAME}_SOURCE_DIR}/src/main.cpp)
# Set the name of the binary file and the output directory
set_target_properties(${MAIN_TARGET_NAME}_executable PROPERTIES OUTPUT_NAME "parent_executable")
set_target_properties(${MAIN_TARGET_NAME}_executable PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${${PROJECT_NAME}_SOURCE_DIR}/bin)
# Set the name of the lib and the output directory
set_target_properties(${MAIN_TARGET_NAME}_lib PROPERTIES RELEASE_OUTPUT_NAME "parent_library")
set_target_properties(${MAIN_TARGET_NAME}_lib PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${${PROJECT_NAME}_SOURCE_DIR}/lib)
target_link_libraries(${MAIN_TARGET_NAME}_executable ${MAIN_TARGET_NAME}_lib)
target_include_directories(${MAIN_TARGET_NAME}_lib PUBLIC
${PROJECT_SOURCE_DIR}/include)
install(TARGETS ${MAIN_TARGET_NAME}_lib
EXPORT parent_Targets
)
# # exporting target from build tree
export(EXPORT parent_Targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/../cmake_export/parent_Targets.cmake"
NAMESPACE cmake_exp_imp_parent::
)
I have build the parent project
cd parent_project
mkdir build && cd build
cmake .. && make
Then I can see in the root of parent project a folder with a generated .cmake file cmake_export/parent_Targets.cmake
Building child proj
CMakeLists.txt from child_project
cmake_minimum_required(VERSION 3.10)
project(child)
# Set the main target name to the project name
set(MAIN_TARGET_NAME ${PROJECT_NAME})
# executable file path
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../bin)
# including the generated cmake of parent proj
include(${CMAKE_BINARY_DIR}/../../parent_project/cmake_export/parent_Targets.cmake)
# get the include header property
get_target_property(PARENT_INCLUDES cmake_exp_imp_parent::parent_lib INTERFACE_INCLUDE_DIRECTORIES)
add_library(${MAIN_TARGET_NAME}_lib SHARED ${${PROJECT_NAME}_SOURCE_DIR}/src/child.cpp)
# Targetting header files for the target ${MAIN_TARGET_NAME}_lib
target_include_directories(${MAIN_TARGET_NAME}_lib PUBLIC ${PROJECT_SOURCE_DIR}/include
${PARENT_INCLUDES})
add_executable(${MAIN_TARGET_NAME}_executable ${${PROJECT_NAME}_SOURCE_DIR}/src/main.cpp)
# Set the name of the binary file and the output directory
set_target_properties(${MAIN_TARGET_NAME}_executable PROPERTIES OUTPUT_NAME "child_executable")
set_target_properties(${MAIN_TARGET_NAME}_executable PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${${PROJECT_NAME}_SOURCE_DIR}/bin)
# Set the name of the lib and the output directory
set_target_properties(${MAIN_TARGET_NAME}_lib PROPERTIES RELEASE_OUTPUT_NAME "child_library")
set_target_properties(${MAIN_TARGET_NAME}_lib PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${${PROJECT_NAME}_SOURCE_DIR}/lib)
target_link_libraries(${MAIN_TARGET_NAME}_executable ${MAIN_TARGET_NAME}_lib
cmake_exp_imp_parent::parent_lib)
I have build the child project
cd child_project
mkdir build && cd build
cmake .. && make
Project is perfectly build.
But i am not satisfied here. Maybe I am decoding the CMake documentation in a wrong way.
Want to know
I have used the following lines i child project CMake file to get the header file of the parent projet. But truly I don't want to use this rather I am inclined to fetch automatically the path from the exported target by importing.
# including the generated cmake of parent proj
include(${CMAKE_BINARY_DIR}/../../parent_project/cmake_export/parent_Targets.cmake)
# get the include header property
get_target_property(PARENT_INCLUDES cmake_exp_imp_parent::parent_lib INTERFACE_INCLUDE_DIRECTORIES)
And then I have appended the variable ${PARENT_INCLUDES}
target_include_directories(${MAIN_TARGET_NAME}_lib PUBLIC ${PROJECT_SOURCE_DIR}/include
${PARENT_INCLUDES})
This helped me to find the header file of parent project.
But my query is as parent project's target is exported so is not is also exported it's all dependencies (I mean the header file path)?
One snipet from the generated cmake file
set_target_properties(cmake_exp_imp_parent::parent_lib PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "Users/cmake_export_import/parent_project/include"
)
Here, i can see that the header file path of the parent project is added. But, how do I use it without using get_target_property? I have found here abpout INTERFACE_INCLUDE_DIRECTORIES and thinking somehow it is available while I use target_link_libraries to link the exported target.
Eg:
target_link_libraries(${MAIN_TARGET_NAME}_executable ${MAIN_TARGET_NAME}_lib
cmake_exp_imp_parent::parent_lib)
Any idea is highly appreciable.

CMAKE creating an additional directory in the build file

My current project structure looks like this:
Project
--src/
--CMakeLists.txt
--Graph.cpp
--Graph.hpp
--main.cpp
--build/
--CMakeLists.txt
The CMakeLists.txt in the Project folder lookalike this:
cmake_minimum_required(VERSION 3.18)
project(GRAPHTHEORY VERSION 1.0.0)
set (CMAKE_CXX_STANDARD 17)
add_subdirectory(src)
the CMakeLists.txt in src file looks like this:
add_library(Graph Graph.hpp Graph.cpp)
add_executable(graph_theory main.cpp)
target_link_libraries(graph_theory PRIVATE Graph )
When I go into the build/ directory, and run cmake .. and then make, the executable graph_theory is in a new src/ directory within build
I am not sure why a new src/ directory is being created in my `build/' directory.
Edit:
So what I was trying to do is replicate running
cmake -S src/ -B build/ from Project directory.
When I do the above and then cd into build/ and then run make, the executable is created in build/ directory.
Build artifacts and cache is kept in a directory that reflect the subdirectory you added in CMake with the add_subdirectory command.
However, you can change where the final target end up by changing the default value of RUNTIME_OUTPUT_DIRECTORY. For example, this code will put it in the bin directory:
set_target_properties(graph_theory
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/"
)

How to best tell CMake where to find dll

I have a simple project structure derived from the amazing tutorial
https://rix0r.nl/blog/2015/08/13/cmake-guide/
It looks as follows:
- src
- CMakeLists.txt
- mylib
- include/mylib/mylibclass.h
- src/mylibclass.cpp
- CMakeLists.txt
- myapp
- src/myapp.cpp
- CMakeLists.txt
The top level CMakeLists.txt contains:
cmake_minimum_required( VERSION 3.6 )
project( sample_project VERSION 0.1 LANGUAGES CXX )
set( BUILD_SHARED_LIBS ON CACHE BOOL "" )
add_subdirectory( mylib )
add_subdirectory( myapp )
The CMakeLists.txt in the mylib folder contains:
add_library( mylib src/mylibclass.cpp include/mylib/mylibclass.h )
set_target_properties( mylib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
target_include_directories( mylib
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> PRIVATE src )
And the one in the myapp folder contains:
add_executable( myapp src/myapp.cpp )
target_link_libraries( myapp mylib )
I want to use this structure to develop both mylib (as a shared or static library as determined by BUILD_SHARED_LIBS) and myapp. For this, I want to set myapp as my startup project in Visual Studio and compile and run in the MSVC debugger. This is not possible for the shared library case without extra CMake code, as the myapp.exe doesn't know where to find the mylib.dll.
What is best CMake practice to tell the program where to find the dll?
Edit:
Based on the suggestions by #Andre, I've added the following lines to the top level CMakeLists.txt:
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out CACHE STRING "" )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out CACHE STRING "" )
The problem occurs, because your mylib.dll is not in the same folder as your myapp.exe nor is it in the %PATH% environment variable when Visual Studio tries to start your myapp.exe
The obvious solution is to make sure both dll and exe are in the same folder. There are several ways to do this:
Put both exe and dll into a single "output" directory by setting the RUNTIME_OUTPUT_DIRECTORY and the LIBRARY_OUTPUT_DIRECTORY properties on your targets:
set_target_properties( myapp PROPERTIES RUNTIME_OUTPUT_DIRECTORY
${sample_project_BINARY_DIR}/build_results/bin )
set_target_properties( mylib PROPERTIES LIBRARY_OUTPUT_DIRECTORY
${sample_project_BINARY_DIR}/build_results/bin )
This will produce the myapp.exe and mylib.dll into a single build_results/bin folder in your top-level build folder.
Or by setting the the global CMAKE_RUNTIME_OUTPUT_DIRECTORY and CMAKE_LIBRARY_OUTPUT_DIRECTORY variables which will do this for all targets in your sample_project.
Copy the dll to the exe location after building, e.g. with
add_custom_command(TARGET mylib
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy mylib.dll ${myapp_BINARY_DIR}/.
)

CMake splits the generated files between build and src directory

My problem is when I run $ cmake /path/to/source/ the resulting files and directories are split between the directory I'm calling from and /path/to/source/include.
Here is my CMake project:
File structure:
root:
|-CMakeLists.txt
|-src
| |-CMakeLists.txt
| |-"source files"
|-include # This is where part of the generated files are ending up.
| |-CMakeLists.txt
| |-"include files"
Here are my CMakeLists.txt's:
root/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(DUCKSIM)
# Add the root directory for the CMakeLists.txt being called. This is necessary for
# out-of-tree builds.
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
# Add the directories containing source and header files.
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/include)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY $(pwd)) # This is an attempt to fix my problem
src/CMakeLists.txt:
# set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Set DUCKSIM_SOURCES as all .cpp files
file(GLOB DUCKSIM_SOURCES *.cpp)
# Set the name of the executable as "ducksim" and link it with main.cpp
# and every thing in the DUCKSIM_SOURCES variable.
add_executable(ducksim main.cpp ${DUCKSIM_SOURCES})
include/CMakeLists.txt:
# set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Set DUCKSIM_SOURCES as all .h files
file(GLOB DUCKSIM_SOURCES *.h)
Command add_subdirectory() will optionally accept a second path as a parameter, but that will indicate the binary directory, as indicated in the documentation. By giving your include folder as the second parameter, CMake assumes that you want the binaries to go there. That's why you end up with some files at the top level (CMakeCache.txt, etc.) and some files in the include folder.
For the record, using file(GLOB ...) is not recommended for collecting source files to compile. If you add a source file, no CMake file will have changed, and the build system won't regenerate.
Finally, you shouldn't need the file(GLOB ...) for the header files, but you probably need an include_directories() call for the include folder.

Building of executable and shared library with cmake, runtimelinker does not find dll

I am working with gcc(cygwin), gnu make, windows 7 and cmake.
my cmake testprojekt has the following structure
rootdir
|-- App
| |-- app.cpp
| +-- CMakeLists.txt
|-- Lib
| |-- lib.cpp
| |-- CMakeLists.txt
|-- MakeFileProject
+ CMakeLists.txt
rootdir/App/app.cpp:
#include<string>
void printThemMessageToScreen(std::string input);//prototype
int main(int argc,char **argv){
printThemMessageToScreen("this will be displayed by our lib");
return 0;
}
rootdir/Lib/lib.cpp:
#include<iostream>
#include<string>
void printThemMessageToScreen(std::string input){
std::cout<<input;
}
rootdir/CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(TestProject)
add_subdirectory(App)
add_subdirectory(Lib)
rootdir/Lib/CMakeLists.txt:
add_library(Lib SHARED lib.cpp)
rootdir/App/CMakeLists.txt:
# Make sure the compiler can find include files from our Lib library.
include_directories (${LIB_SOURCE_DIR}/Lib)
# Make sure the linker can find the Lib library once it is built.
link_directories (${LIB_BINARY_DIR}/Lib)
# Add executable called "TestProjectExecutable" that is built from the source files
add_executable (TestProjectExecutable app.cpp)
# Link the executable to the lib library.
target_link_libraries (TestProjectExecutable Lib)
Now, when i run cmake and make, everything will get generated & built with no errors, but when i try to execute the binary, it will fail because the library which was generated could not be found.
BUT: when i copy the lib dll into the same directory like the app exe, it will get executed!
also: if i configure the library to be static, it will also execute.
how to tell the runtime linker where to look for my dll?
UPDATE:
Solution according to the Method proposed by User Vorren:
I opened up the registry editor, and navigated to the following Key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
, here i created a new key with the name of my Applikation:
in this case : TestProjectExecutable.exe
after that, the (default) value was set to the full path of TestProjectExecutable.exe including the filename and extension. Then i created another String Value called "Path" and set the value to the folder where the dll was located:
Your problem lies not with linker or compiler, but with the way Windows searches for DLL's.
The OS will use the following algorithm to locate the required DLL's:
Look in:
The directories listed in the Application-specific Path registry key;
The directory where the executable module for the current process is located;
The current directory;
The Windows system directory;
The Windows directory;
The directories listed in the PATH environment variable;
Thus you have two reasonable options if you don't want to clutter the OS directories with your app-specific dll:
Create an app-specific Path registry entry (I would go with this option);
Put your DLL in the same folder as your EXE;
Modify the PATH variable (but why would you do that, if you can go with option 1?);
A solution I prefer that hasn't really been mentioned, is build your shared-libs into the same directory as your executables. This tends to be a much simpler solution.
One way to do this with cmake is
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
Or you can also set output directories based on build flavours.
See how do I make cmake output into a 'bin' dir?
I discovered (what I believe to be) quite a nice way of handling this. It follows the approach of adding the .dll to the same directory as the .exe. You can do it in CMake like so:
if (WIN32)
# copy the .dll file to the same folder as the executable
add_custom_command(
TARGET <app-target> POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
$<TARGET_FILE_DIR:<lib-target>>
$<TARGET_FILE_DIR:<app-target>)
endif()
where app-target is the name of the application or library you're building (created through add_executable or add_library) and lib-target is the imported library brought in with find_package.
# full example
cmake_minimum_required(VERSION 3.14)
project(my-app-project VERSION 0.0.1 LANGUAGES CXX)
find_package(useful-library REQUIRED)
add_executable(my-application main.cpp)
target_link_libraries(my-application PUBLIC useful-library::useful-library)
if (WIN32)
# copy the .dll file to the same folder as the executable
add_custom_command(
TARGET my-application POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
$<TARGET_FILE_DIR:useful-library::useful-library>
$<TARGET_FILE_DIR:my-application>)
endif()
I tried the option 1 from accepted answer (by pdeschain).
I even created a cmake hook to register paths of linked libraries automatically
function (xtarget_link_libraries target libs) # same as target_link_libraries but with additional improvements to allow windows find the library at runtime
LIST(REMOVE_AT ARGV 0)
SET(LIBS ${ARGV}) # this is to pass list into this function
target_link_libraries(${target} ${LIBS}) # call standard routine
if(WIN32)
set(TFILE ".")
get_property(slibs TARGET ${target} PROPERTY all_libs) # recall libs linked before
set(LIBS ${slibs};${LIBS})
set_property(TARGET ${target} PROPERTY all_libs ${LIBS}) # save all libs
FOREACH(lib ${LIBS}) # compose a list of paths
set(TFILE "${TFILE};$<TARGET_LINKER_FILE_DIR:${lib}>")
ENDFOREACH()
#add reg key
add_custom_command(TARGET ${target} POST_BUILD COMMAND reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${target}.exe" /v "Path" /d "${TFILE}" /f )
endif()
endfunction()
Can be used as xtarget_link_libraries(test lib1 lib2). The application will be able to find dynamic libraries at their absolute paths.
BUT, there is a big problem with this, that the App Paths mechanism https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx#appPaths
does not allow to have different entries for say 'Debug/test.exe' and 'Release/test.exe'. So to me this is a poor option.
You may add the following line to fill the Default key as path to the program as suggested in the post.
add_custom_command(TARGET ${target} POST_BUILD COMMAND reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${target}.exe" /ve /d "$<TARGET_FILE:${target}>" /f )
Now you can enjoy running test.exe from anywhere in the system... I guess my next try will be option
Create symbolic links to dlls with cmake.