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
Related
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 ...)
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)
I have a CMake 3.5.2 project that creates a library: libtest.a, which is then linked to by an executable.
The source code is Fortran, and the libtest.a produces a module file: "main.mod"
The executable also needs to include this main.mod file, so to make main.mod accessible, when building the project I set the variable, CMAKE_Fortran_MODULE_DIRECTORY to a known location, and add it to the relevant include paths.
This works great when building the entire project, main.mod is built in a known location, and it is there for whatever code needs it. My usage, however, makes it necessary to only build libtest.a by itself, and leave the executable to be built by a downstream user sometimes.
The issue I am having is that when I go into the libtest source and treat it as its own CMake project, the library will build and install, but the main.mod file is always left in the BINARY_DIR and is not built in the CMAKE_Fortran_MODULE_DIRECTORY, dispite setting in the the CMakeList.txt within libtest.
Is the Fortran_MODULE_DIRECTORY only honored when add_executable() is being called? And just ignored for the library builds alone? Or am I missing something.
Thanks for the help.
EDIT: This will reproduce my issue.
test_mod.f90:
module main
implicit none
real, parameter :: pi=3.2
end module main
tt.f90:
program test
use main
implicit none
real :: a, area
a =10
area = a * 100
end program test
CMakeList.txt:
CMAKE_minimum_required( VERSION 3.5 )
enable_language( Fortran )
project( tt )
file( GLOB test_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.f90 )
add_library( tt STATIC ${test_SOURCES} )
set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Mod )
install( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Lib/ )
If I build and install the above code, I will get a libtt.a library installed in the Lib directory, however my main.mod will remain in my build directory and is not build in a Mod folder.
Here I assume that the "user" uses cmake to build the project while having access to the source of your project.
The steps to a working build.
There is a CMakeLists.txt file for libtest that specifies CMAKE_Fortran_MODULE_DIRECTORY. This should be enough for main.mod to appear there.
There is a CMakeLists.txt file for buiding the "client" program. This file should include the libtest project with add_subdirectory.
Add target_link_libraries(NAME_OF_PROGRAM NAME_OF_LIBRARY). This only takes care of the linking of libraries and is not sufficient (for solution B below anyway) for the module to be known to the client program.
Now, make your own adventure:
Solution A: in the libtest CMakeLists.txt, place the module where "all modules will go", for instance set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/modules) (you need to do this also for the "client" CMakeLists.txt). The variable ${CMAKE_BINARY_DIR} is set by the "client" cmake invocation and will be the same for all included cmake projects. This directory will be listed in the build commands for Fortran programs.
Solution B: in the libtest CMakeLists.txt, place the module of this library in a dedicated directory. You can achieve this, for instance, with set(CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/modules). You need then to manually specify this location with include_directories(PATH_THAT_DEPENDS_ON_THE_NAME_OF_THE_SUBPROJECT) in the client CMakeLists.txt.
If you wish the library to be installable, you need to specify paths for installing the library and the module file. With Fortran, you should think of this with the target OS, compiler and architecture in mind.
Links to the CMake documentation:
PROJECT_BINARY_DIR
CMAKE_Fortran_MODULE_DIRECTORY
CMAKE_BINARY_DIR
Following the addition of your sample code, the following modification should do it:
CMAKE_minimum_required( VERSION 3.5 )
enable_language( Fortran )
project( tt )
set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Mod )
file( GLOB test_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.f90 )
add_library( tt STATIC ${test_SOURCES} )
install( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Lib/ )
install(DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR})
Make sure that set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Mod ) occurs before any add_library line.
Add install(DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}) to actually install the .mod file. Module files (as header files in C) have to installed in addition to the library file.
The setup you created is a bit unusual in that you locate everything within the source build whereas "usual" install locations are made relative to CMAKE_INSTALL_PREFIX
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.
I would like to set up a new project using CMake.
My working dir is the following :
CMakeLists.txt
include
- file1.h
src
- file1.cpp
- CMakeLists.txt
tests
- test1.cpp
- CMakeLists.txt
The main CMakeList.txt is the following:
cmake_minimum_required(VERSION 2.8)
project(bench CXX)
include_directories(include)
subdirs(src tests)
The src CMakeList.txt is :
add_library(foo SHARED file1.cpp)
install(TARGETS foo DESTINATION lib)
And the tests CMakeList.txt is:
add_executable(test1 test1.cpp)
target_link_libraries(test1 foo)
install(TARGETS test1 DESTINATION bin)
I would expect the files to be located in
<build_dir>/bin/test1
<build_dir>/lib/libfoo.so
But instead they are organized like this :
<build_dir>/src/test1
<build_dir>/tests/libfoo.so
What am I doing wrong ?
Thanks in advance,
You are giving instructions for the install step/build target, which is independent from the build tree under <binary_dir>.
Set CMAKE_INSTALL_PREFIX to a folder of your choice and run make install (assuming make build system here) after your build. The you will find CMAKE_INSTALL_PREFIX/lib/libfoo.so and CMAKE_INSTALL_PREFIX/bin/test1 as you told cmake. The DESTINATION path is always relative to CMAKE_INSTALL_PREFIX (unless you specify an absolute path, of course).
The compiled libs and binaries within the build tree (i.e. <build_dir>) will always reflect the source tree structure with respect to location; this cannot be changed and is not the intended way of use.
Generally there are three different "things": Source/Build/Install trees. The build tree mirrors the source tree structure and contains cmake-generated extra files and objects. The install "tree" is a setting of your choice, where CMAKE_INSTALL_PREFIX is the root directory under which libraries, archives and binaries are placed. You can control the behaviour completely (what you already intend to do!), although there are reasonable default settings.