Can I add a library from the folder above? - cmake

I can't add my static library to my project.
I have the following project structure:
+ root/
+ CmakeLists.txt // Include all projects
+ Base/
| + foo.cpp
| + CmakeLists.txt
+ App1/
| + app1.cpp
| + CmakeLists.txt // Requires Base lib
+ App2/
| + app2.cpp
| + CmakeLists.txt // Requires Base lib
I try to do it in the following way:
Base CmakeLists.txt:
cmake_minimum_required(VERSION 3.10.2)
add_library(Base STATIC foo.cpp)
App1 CmakeLists.txt:
cmake_minimum_required(VERSION 3.10.2)
project(App1)
add_executable(${CMAKE_PROJECT_NAME} app1.cpp)
include(../Base/CMakeLists.txt)
But I have the following error:
CMake Error at C:/DPA/Base/CMakeLists.txt:3 (add_library):
Cannot find source file:
foo.cpp
How I can properly setup library to include in all projects?

That's not how you use such a directory structure. Instead, in App1/CmakeLists.txt, go with
add_executable(App1 app1.cpp)
target_link_libraries(App1 Base)
This declares that App1 depends on Base and shall be linked against that library. "Linking" means not only passing the correct arguments to your linker, it also propagates include flags and other options to the compiler when building App1 sources.
If you intend to build only parts of your project, you can use an additional argument to add_executable, i.e.
add_executable(App1 EXCLUDE_FROM_ALL app1.cpp)
This way, when you build the default target, App1 won't be part of the build. You can still build it manually/upon request, e.g. when working with makefiles,
make App1
will build the executable App1 and everything that's required for it.

Related

Copy compilation/linking settings from project in CMake object library?

I'm in a similar situation to Adding object-file dependencies where it is mentioned:
... I need some object files that are part of the same library to be compiled before others.
Don't try to declare dependencies between object files. If there are files that have a dependency, break them out into a separate library with add_library and then declare the dependency with add_dependencies and target_link_libraries. There is no extra cost for doing this. Particularly, consider looking at Object Libraries.
I tried to implement this in my original project, where I'm working with a massive CMakeLists.txt file, where include & linker paths may be conditionally inserted or removed, and I failed. In essence, that CMakeLists.txt file would looks like this simplified:
project(MY_PROGRAM C CXX ASM)
set(MY_PROGRAM_sources
main.c
file_one.c
file_two.c
)
add_executable(MY_PROGRAM ${MY_PROGRAM_sources})
target_include_directories(MY_PROGRAM PRIVATE
${CUSTOM_PATH}/src/custom/include
...
)
add_compile_options(-Wall
-Wno-format
...
)
target_link_libraries(MY_PROGRAM
somelib1
somelib2
)
This builds fine, using Unix Makefiles.
Now, I've tried to extract file_one and file_two objects like this:
project(MY_PROGRAM C CXX ASM)
set(MY_PROGRAM_sources
main.c
#file_one.c
#file_two.c
$<TARGET_OBJECTS:SEPFILE_OBJS>
)
add_library(SEPFILE_OBJS OBJECT
file_one.c
file_two.c
)
add_executable(MY_PROGRAM ${MY_PROGRAM_sources})
target_include_directories(MY_PROGRAM PRIVATE
${CUSTOM_PATH}/src/custom/include
...
)
add_compile_options(-Wall
-Wno-format
...
)
target_link_libraries(MY_PROGRAM
somelib1
somelib2
)
cmake passes fine here, but when I hit make, there is breakage as soon as file_one.c starts compiling:
...
[ 9%] Building C object CMakeFiles/SEPFILE_OBJS.dir/file_one.c.obj
In file included from C:/tmp/file_one.c:14:
C:/tmp/file_one.h:19:10: fatal error: ExoticHeader.h: No such file or directory
19 | #include <ExoticHeader.h>
Clearly, the SEPFILE_OBJS library did not inherit the include libraries nor other compilation/linker settings from the MY_PROGRAM executable.
I could probably repeat all target_* lines for SEPFILE_OBJS - but that looks quite unmanageable, plus my original CMakeLists.txt is huge, and I'd like to avoid that kind of work.
So is there a way to say to CMake "keep the same compilation and linker settings as in executable for MY_PROGRAM, also for the object library SEPFILE_OBJS"?
I would do it the way around. I would first define a library section, including file_one.c and file_two.c, and then a main executable section, which would link against this library target.
I would also follow something along the lines below for a directory structure (ideally, I would put the source files within a src directory):
/ MY_PROGRAM
|- include
| \- MY_PROGRAM
| |- file_one.h
| \- fine_two.h
|- file_one.c
|- file_two.c
|- main.c
\- CMakeLists.txt
Put your header files in an include/${PROJECT_NAME} folder, and set an include_dir var pointing to it.
set(include_dir ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME})
Define the list of library and application sources:
set(lib_sources
"${CMAKE_CURRENT_SOURCE_DIR}/file_one.c"
"${CMAKE_CURRENT_SOURCE_DIR}/file_two.c"
)
set(app_sources
"${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
)
Library section. Define a lib_MY_PROGRAM target, and set the include directories, compile options, and link libraries for it. Notice it's better to use the target_... specific commands than the more general ones, such as add_compile_options:
add_library(lib_${PROJECT_NAME} ${lib_sources})
target_include_directories(lib_${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${include_dir}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_include_directories(lib_${PROJECT_NAME} SYSTEM PUBLIC
${CUSTOM_PATH}/src/custom/include
)
target_compile_options(lib_${PROJECT_NAME} PRIVATE
-Wall
-Wno-format
)
target_link_libraries(lib_${PROJECT_NAME} PRIVATE
somelib1
somelib2
)
Main binary section:
add_executable(${PROJECT_NAME} ${app_sources})
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${include_dir}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_compile_options(lib_${PROJECT_NAME} PRIVATE
-Wall
-Wno-format
)
target_link_libraries(${PROJECT_NAME} PRIVATE lib_${PROJECT_NAME})

Internal dependencies with cmake in a large project

I have a project with multiple libraries which have dependencies between them.
It looks similar to this:
project
+ libs
| + lib1
| + lib2
| + lib3
+ apps
| + app1
| + app2
I have dependencies between different targets. For example, lib2 depends on lib1 and lib3 depends on lib2 (note transitive dependency here). Apps mostly depends on arbitrary number of libs.
I would like to have a CMakeLists.txt in the project root and in each library and application folder.
I assume that in the main CMakeLists.txt I will use add_subdirectory() to include other CMakeLists.txt files but I'm not sure what is the best practice to reflect dependencies between different targets (library on other libraries and application on libraries) since they reside on the same level. In other words I would like to know how CMakeLists.txt for lib2 and lib3 could look like.
Update:
I managed to find a potential solution: people suggest to use add_dependencies(lib1 lib2). Should this be specified before all the add_subdirectory()?

How to add C++REST SDK as a submodule with CMake?

I am trying to build a project with numerous dependencies such as Boost, OpenSSL, and C++ REST SDK. However, it is required that the source code is included in the project workspace and that the library is built from said source code.
The most consistently successful way I have found to achieve this is though the use of git submodule add <URL>, add_subdirectory, target_link_libraries, and some clever projects built for this purpose such as boost-cmake and openssl-cmake.
Take for example the following project structure:
prjct
| include/
| libs/
| | boost-cmake/
| | openssl-cmake/
| | cpprestsdk/
| src/
| tests/
| CMakeLists.txt
For which the top-level CMakeLists.txt would contain:
...
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/boost-cmake)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/openssl-cmake)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/cpprestsdk)
target_link_libraries(${PROJECT_NAME_L}
PUBLIC
Boost::system
Boost::thread
Boost::log
Boost::program_options
Boost::chrono
ssl # OpenSSL::SSL
crypto # OpenSSL::Crypto
cpprestsdk::cpprest
)
...
However, in the case of the cpprestsdk library, I recieve the following error upon running cmake .. from build/:
CMake Error at CMakeLists.txt:55 (add_library):
Target "prjct" links to target "cpprestsdk::cpprest" but the target
was not found. Perhaps a find_package() call is missing for and IMPORTED
target, or an ALIAS target is missing?
How can I link and use the C++ REST SDK within these constraints?

Cmake add external project?

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)

Overlapping dependencies between libraries in CMake

Let's say there's the following directory structure:
projects
|
+--lib1
| |
| +-CMakeFiles.txt
|
+--lib2
| |
| +-CMakeFiles.txt
|
+--test
|
+-CMakeFiles.txt
lib1/CMakeFiles.txt:
cmake_minimum_required(VERSION 2.0)
add_library(lib1 STATIC lib1.cpp)
lib2/CMakeFiles.txt:
cmake_minimum_required(VERSION 2.0)
add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1)
add_library(lib2 STATIC lib2.cpp)
target_link_libraries(lib2 lib1)
test/CMakeFiles.txt:
cmake_minimum_required(VERSION 2.0)
project(test)
add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1)
add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2)
add_executable(test main.cpp)
target_link_libraries(test lib1 lib2)
I.e. lib2 depends on lib1 and test depends on both of them. (I know that technically static libraries don't "link", but that's just an example.)
The problem is that with the current setup, lib1 compiles twice - the first time it is within the "test" build directory, and a second time it is within "test/build_directory/lib2/build_directory". I'd like to avoid that.
I want to be able to add a dependency on lib1, lib2 or both of them (using add_subdirectory) to any project that's located elsewhere. So moving CMakeFiles isn't an option. I also want to avoid compiling any library several times.
How can I do that?
Platform: CMake v. 2.8.4 and Windows XP SP3
A top-level CMakeLists.txt file isn't an option, because I want to keep a clean top-level directory and be able to include libraries in other projects that can be located elsewhere. Because it is Windows, I can't "install package system-wide" - I don't want to lose ability to switch compiler on the fly. Utility libraries built with different compilers will use different C runtime libraries/ABI, and as a result will be incompatible.
One other solution is to add a guard at the top of the subdirectory-CMakeLists.txt:
if(TARGET targetname)
return()
endif(TARGET targetname)
Which will cause cmake to do nothing the second time the subdirectory is added (if targetname is being defined in that file, of course).
This will lead to the lib beeing build in an sort-of-arbitrary place (depending on which module added it first) in the build/ tree, but it will be built only once and linked everywhere.
In your example, you would add
if(TARGET lib1)
return()
endif(TARGET lib1)
at the top of lib1/CMakeFiles.txt
With CMake, library dependencies are transitive, so you shouldn't call add_subdirectory twice in test/CMakeFiles.txt (nor do you need to list lib1 as a dependency of test since it is already a dependency of lib2's).
So you could modify test's CMakeFiles.txt to:
cmake_minimum_required(VERSION 2.8.7) # Prefer the most current version possible
project(test)
add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2)
add_executable(test main.cpp)
target_link_libraries(test lib2)
Also, you should probably remove the cmake_minimum_required calls from your non-project CMakeFiles.txt files (the lib ones). For further info, run:
cmake --help-policy CMP0000
This setup will still cause all libs to be recompiled if you add a similar test2 subdirectory and project which depends on lib1 and lib2. If you really don't want to have a top-level CMakeFiles.txt in projects/, then you're stuck with what you're doing, or you could use either the export or install command.
export would create a file which could be included by other projects and which imports the targets into the project which calls include.
install could install the libraries to another common subdirectory of projects/. Depending on your source directory structure, this could have the benefit of only making the intended library API headers available to dependent projects.
However, both of these options require the dependent library projects to be rebuilt (and installed) if they are modified, whereas your current setup includes all the dependent targets in your project, so any change to a source file in a dependent library will cause your test target to go out of date.
For further details about export and install, run:
cmake --help-command export
cmake --help-command install
Perhaps add a top-level CMakeLists.txt in your projects dir. Something like:
project( YourProjects )
add_subdirectory( lib1 )
add_subdirectory( lib2 )
add_subdirectory( test )
This should be sufficient and will give you a solution-file or makefile in your top-level build-dir. You should then remove the add_subdirectory( ../lib1 ... from your lib1 and lib2 projects, but instead simply link to them. CMake will know how to find lib1 and lib2 when compiling test.
I.e. in lib2:
project( lib2)
add_library(lib2 STATIC lib2.cpp)
target_link_libraries(lib2 lib1)
and in test:
project( test )
add_executable(test main.cpp)
target_link_libraries(test lib1 lib2)
Added bonus: you will get makefiles/solutionfiles for building lib2 (with dependent lib1) in the lib2 directory...