Cmake add external project? - cmake

I'm not entirely sure if externalproject_Add as most of the examples I can find on it is about downloading git etc/but maybe thats it...
Esentially I have :
FolderA // inherited project
> main.cpp
> CMakeList.txt
> libFolder
>someStuff.h
>someStuff.cpp
FolderB // base project
> main.cpp
> CMakeList.txt
> libFolder_Core
>someStuff_Core.h
>someStuff_Core.cpp
I want to "not" have to build static/dynamic/etc lib every time I make a change to project in folderB, I just want to include the CMakeList.txt from that folder in my folderA, FolerB cmake only has something like
set(headers xx.h)
set(source xx.cpp)
set(all ${headers} ${source})
Just looking for a way to say in projectA, cmake,
get_filename_component(libs"${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)
SET(coreLib ${libs}/someCoreLib/)
add_executable(name, main.cpp ${coreLib})
Is something like that possible?

You can do that easily with mordern CMake using exported target.
In project A:
add_library(projecta a.cpp b.cpp c.cpp)
add_library(projecta::projecta ALIAS projecta)
target_include_directories(projecta PUBLIC ...)
install(TARGETS projecta EXPORT projectaTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
install(
EXPORT projectaTargets
NAMESPACE projecta::
FILE projectaConfig.cmake
DESTINATION lib/cmake/projecta
)
export(
EXPORT projectaTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/projectaConfig.cmake"
)
This will make a target for projecta and export the targets for other project to use them.
If the project A itself has dependencies, consider exporting the targets to a target file, then generate a config file that also find the package of your dependencies. More on that on the It's Time To Do CMake Right blog post.
Simply add the path of your build directory in the CMake module path in the command line: -DCMAKE_PREFIX_PATH=/path/to/projecta/build
Then, in project B:
find_package(projecta REQUIRED)
add_executable(projectb x.cpp y.cpp z.cpp)
# link project b to project a,
# adding include directories and link dependencies
target_link_libraries(projectb PUBLIC projecta::projecta)

Related

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 ...)

Using CMAKE_DEBUG_POSTFIX with exported targets

When I use set(CMAKE_DEBUG_POSTFIX "d"), the build and install targets work as expected. But in the libfooTargets-debug.cmake file with the exported targets, there is a path to libfoo and not libfood.
I exported the targets like this:
install(TARGETS libfoo EXPORT libfoo-targets LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin)
install(EXPORT libfoo-targets FILE libfooTargets.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
which creates and installs libfooTargets.cmake and libfooTargets-debug.cmake when building in debug mode, and libfooTargets.cmake and libfooTargets-release.cmake when building in release mode.
Both libfooTargets-release.cmake and libfooTargets-debug.cmake reference the name without a postfix as:
list(APPEND _IMPORT_CHECK_FILES_FOR_libfoo "${_IMPORT_PREFIX}/lib/libfoo.lib" )
and thus a program linking against the debug target still uses the release-build library and I would need to install release and debug versions into different folders to be able to link against the debug target.
How can I get the exported targets to work with a debug postfix?
I could of course try to change the library name depending on CMAKE_RELEASE_TYPE or a CONFIGURATION generator expression, but this will probably break the multi-configuration features in MSVC and other IDEs supporting different targets and seems not to work in the sense of how the exported targets feature is meant to simplify and unify the build.
I suspect that the install(EXPORT ...) command somehow drops the CMAKE_DEBUG_POSTFIX or does not implement it for generating the libfooTargets-{release,debug}.cmake files, but possibly I overlooked how to make this variable visible to the generator of the exported targets or something like this.
All target code
cmake_minimum_required(VERSION 3.11.1)
project(foo)
include(CMakePackageConfigHelpers)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_DEBUG_POSTFIX "d")
# ...
add_library(libfoo STATIC somesource.cpp someheader.h)
target_include_directories(libfoo PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
target_link_libraries(libfoo
somelibrary
)
target_include_directories (libfoo PUBLIC
somelibrary_header_dirs
)
install(TARGETS libfoo EXPORT libfoo-targets LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin)
install(EXPORT libfoo-targets FILE libfooTargets.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
configure_package_config_file(libfooConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libfooConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libfooConfig.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h")
The platform is a Windows 10 with cmake 3.11.1 and MSVC 2015. Of course the most general solution is probably the best one.
According to the documentation of the install command, you need to reference the configuration that you are interested in:
[...] If a CONFIGURATIONS option is given then the file will only be installed when one of the named configurations is installed. Additionally, the generated import file will reference only the matching target configurations. [...]
So, you need to add the CONFIGURATIONS option in both install commands and duplicate the commands for each configuration you want to install and export.

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: include a directory into parent from within a subdirectory (aka library)

I have a small project with this structure:
myproject/
mylib/
include/
src/
myprog/
include/
src/
I added a CmakeLists.txt file into myproject and added the subdirectory mylib and myprog. The subdirectories got a CMakeLists, too. Now, when I run cmake, both modules are built correctly, unless I want to use mylib in myprogram. I've found solutions where the global CmakeLists defines an include_directories. But I would prefer to define this in mylib such that mylib/include is added to the project' include path. I would like a project of submodules where each submodule defines it's sources and includes and the project's CMakeLists only connects the modules together. How can I do that? Is that what I try to achieve recommanded? (cmake newbie)
You want target_include_directories. See http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html

Moving Headers/Libraries/Executables to specific directories

I've recently started using CMake for one of my multi-platform projects, but I'm having a little trouble figuring out how to do something.
Basically, inside the project I've got multiple libraries and executables, all in their own folders. I would like to place all of the compiled libraries into one directory on build i.e. a lib folder inside the CMake build folder. I would like to do the same things for the executables.
CMake Build Directory
| ----------> bin (where i want the executables to go)
| ----------> lib (where i want the libraries to go)
| ----------> utils (where the libraries are ordinarily compiled)
| ----------> test (where the executables are ordinarily compiled)
There are directories inside utils and apps for all the different libraries and executables I'm making. I have a CMakeLists in the base folder of my source directory which adds all the subdirectories. If anything does not make sense then feel free to ask.
You can also use this:
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 )
Look at install CMake command.
Here example from that page:
install(TARGETS myExe mySharedLib myStaticLib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(TARGETS mySharedLib DESTINATION /some/full/path)
So you can use CMAKE_BINARY_DIR instead /some/full/path
In addition, for includes:
install( FILES ${HEADERS}
DESTINATION inc )
[when set of header files to be installed]
install( DIRECTORY include/${PROJECT_NAME}/
DESTINATION inc)
[when header directory to be installed]
More Info