I have a problem building a CMake project with a static library.
My project strucutre looks like that:
Foo/
|-- CMakeLists.txt
|-- lib/
|-- CMakeLists.txt
|-- libA/
|-- CMakeLists.txt
|-- libA.cpp
|-- libA.h
|-- libAB.h
|-- src/
|-- CMakeLists.txt
|-- main.cpp
|-- srcDirA/
|-- CMakeLists.txt
|-- srcA.h
|-- srcDirB/
|-- CMakeLists.txt
|-- srcB.cpp
|-- srcB.h
And the */CMakeLists.txt look like that:
Foo/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5.1)
project(FOO)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(lib)
add_subdirectory(src)
Foo/lib/CMakeLists.txt:
add_subdirectory(libA)
Foo/lib/libA/CMakeLists.txt:
add_library (staticLibA STATIC libA.cpp)
Foo/src/CMakeLists.txt:
add_subdirectory(srcDirA)
add_subdirectory(srcDirB)
include_directories(".")
add_executable(foo main.cpp)
target_link_libraries(foo LINK_PUBLIC libA)
Foo/src/srcDirA/CMakeLists.txt is empty
Foo/src/srcDirB/CMakeLists.txt is empty
Now I am trying to include the header from my static library into my main project like this:
Foo/src/main.cpp:
#include "srcDirB/srcB.h"
#include "libA/libA.h"
int main() {
//...
return 0;
}
If I try to build this with CMake, libA is generated but I am getting a fatal error:
libA/libA.h: No such file or directory.
Does anyone know what I am doing wrong? Do I have to create a ProjectConfig.cmake file?
You don't need to create any Config files; these are for importing 3rd-party projects.
Since you're using CMake >= 3.5.1, you can esaily specify usage requirements for your libraries. Usage requirements are things like flags or include directories which clients need to build with the library.
So in Foo/lib/libA/CMakeLists.txt:, you'll do this:
add_library (staticLibA STATIC libA.cpp)
target_include_directories(staticLibA INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/..)
Or, if you want the same include directory to apply to libA itself (which is likely), use PUBLIC instead of INTERFACE.
That's all you really need to do. However, given the modern CMake you're using, you should replace your use of the legacy keyword LINK_PUBLIC with its modern equivalent PUBLIC.
Also, since you mention both CMakeLists in .../srcDir* are empty, why have them there in the first place? You can easily get rid of both them and the related add_subdirectory calls.
Related
For my research project I am setting up a project (coom) to benchmark a set of algorithms on a data structure. For unit testing I settled on Bandit, which leaves me with a project structure that looks as follows:
+ root
|-- CMakeLists.txt
|-+ external/
| \-- bandit/
|-+ src/
| |-- CMakeLists.txt
| |-- node.cpp
| \-- node.h
\-+ test/
|-- CMakeLists.txt
|-- test.cpp
\-- test_node.cpp
From my experience with other languages, this seems to me a standard project structure? The test/ folder contains unit tests for the logic in src/ and no dependencies are intermixed with the source and test code, but are instead in external/.
The testing files I want to look as follows (with irrelevant parts removed)
// test/test.cpp
#include <bandit/bandit.h>
(...)
#include "test_node.cpp"
int main(int argc, char* argv[]) {
(...)
}
// test/test_node.cpp
#include <coom/node.h>
(...)
But my problem is, that when I try to compile with cmake .. and the subsequent Makefile, they are unable to find the source code in src/ where I get the compiler error:
fatal error: coom/node.h: No such file or directory.
I would expect the test/CMakeLists.txt should look somewhat like the following:
# test/CMakeLists.txt
add_executable (test_unit test.cpp)
target_link_libraries(test_unit coom)
I cannot figure out how to setup the CMakeLists.txt and src/CMakeLists.txt to ensure I get the desired outcome above. Currently they look as follows:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project (coom VERSION 0.1)
# ============================================================================ #
# Dependencies
(...)
# ============================================================================ #
# COOM project
add_subdirectory (src)
add_subdirectory (test)
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
node.h
)
set(SOURCES
node.cpp
)
add_library(coom ${HEADERS} ${SOURCES})
I can see from other projects, that it is possible to link the src/ directory with some libname/ prefix, but I cannot discern from their CMakeLists.txt files what I am doing wrong. I have looked at writing a coom.pc.in file and providing an install-target, and tried to set_target_properties with either FOLDER coom or PREFIX coom, but neither worked. I can hack an include_directory(../src) into the test/CMakeLists.txt to be able to include the file via an #include <node.cpp>, but that screams I'm doing something inherently wrong.
I'm at this point very much pulling my hairs out, and the CMake documentation is of very little help to me.
Your coom target has no include directories defined. You can define the include directories to use for this target (with target_include_directories()), and propagate these include directories so they are visible to the consuming test_unit target (by using PUBLIC):
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
node.h
)
set(SOURCES
node.cpp
)
add_library(coom ${HEADERS} ${SOURCES})
target_include_directories(coom PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Furthermore, the file path to the node.h header is coom/src/node.h, not coom/node.h. But, because you now have coom/src as an public include directory, you can use the following to include the node.h header in your test file:
#include <node.h>
I decided to try CMake for my new project. I've spent some hours reading the official documentation and tutorials so I've gained some basic knowledge, but unable to write proper CMakeLists for my project.
The file hierarchy looks like this:
project
|-- library
| |-- CMakeLists.txt
| |-- lib.cpp
| `-- lib.h
|-- app1
| |-- CMakeLists.txt
| |-- app1.cpp
| |-- app1.h
| `-- main.cpp
|-- app2
| |-- CMakeLists.txt
| |-- app2.cpp
| |-- app2.h
| `-- main.cpp
`-- app3
|-- CMakeLists.txt
|-- app3.cpp
|-- app3.h
`-- main.cpp
The point is that I want to compile the library as a static library so it can be used by app1, app2, app3 and so on. The reason for this structure is that each appN has it's own main function that will be run on AWS Lambda, but I'd like to write some common code shared between them in the library.
From what I've read so far it's easy to add a library if it was in a sub-directory of the appN using add_directory() and add it to the target_link_libraries(), but I cannot figure out how to add a library that is outside of the appN folders. I tried using relative paths like ${CMAKE_CURRENT_SOURCE_DIR}/../library/lib.a etc, but then CMake gives error that library is outside project folder.
I'm sure there is some way to do this. I've read some about CMake modules and find_package(), but it seems to be a bit overkill/complicated for this use-case, I think?
Wouldn't something like this work in a main CMakeLists.txt (where you create the PROJECT)?
ADD_LIBRARY(MyLib STATIC library/lib.cpp library/lib.h)
ADD_EXECUTABLE(app1 STATIC app1/app1.cpp app1/app1.h)
ADD_EXECUTABLE(app2 STATIC app2/app2.cpp app2/app2.h)
ADD_EXECUTABLE(app3 STATIC app3/app3.cpp app3/app3.h)
TARGET_LINK_LIBRARIES(app1 MyLib)
TARGET_LINK_LIBRARIES(app2 MyLib)
TARGET_LINK_LIBRARIES(app3 MyLib)
I ended up creating a main CMakeLists.txt that includes the subdirectories which again has their CMakeLists.txt. I found this approach to be the cleanest.
If someone else come by this I've included my complete CMakeLists.txt files below for reference along with the updated file hierarchy.
File hierarchy
project
|-- CMakeLists.txt
|-- library
| |-- CMakeLists.txt
| |-- lib.cpp
| `-- lib.h
|-- app1
| |-- CMakeLists.txt
| |-- app1.cpp
| |-- app1.h
| `-- main.cpp
|-- app2
| |-- CMakeLists.txt
| |-- app2.cpp
| |-- app2.h
| `-- main.cpp
`-- app3
|-- CMakeLists.txt
|-- app3.cpp
|-- app3.h
`-- main.cpp
CMakeLists.txt
project(MyProject)
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(library)
add_subdirectory(app1)
add_subdirectory(app2)
add_subdirectory(app3)
library/CMakeLists.txt
project(library)
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 11)
add_library(${PROJECT_NAME} STATIC lib.cpp lib.h)
target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
app1/CMakeLists.txt
project(app1)
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 11)
add_executable(${PROJECT_NAME} main.cpp app1.cpp app1.h)
target_link_libraries(${PROJECT_NAME} library)
app2/CMakeLists.txt
project(app2)
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 11)
add_executable(${PROJECT_NAME} main.cpp app2.cpp app2.h)
target_link_libraries(${PROJECT_NAME} library)
app3/CMakeLists.txt
project(app3)
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 11)
add_executable(${PROJECT_NAME} main.cpp app3.cpp app3.h)
target_link_libraries(${PROJECT_NAME} library)
I'm trying to use cmake for the first time and I'm having a hard time getting this to work. There's a source file and a library file (Lab_4.cpp and Trip_4.cpp, respectively) and they're both in the source folder (Lab_4). Here's what's in my cmake file so far:
cmake_minimum_required (VERSION 2.6)
project (Lab_4)
#add executable
add_executable(Lab_4 ${PROJECT_SOURCE DIR}/Lab_4.cxx)
target_link_libraries (Lab_4 ${EXTRA_LISTS})
#add libraries
add_library (${PROJECT_SOURCE_DIR}/Trip.cxx)
ls shows both files are in that folder. I'm really new to cmake so I'm sure I'm making an obvious mistake but I have no idea what it is. Any help would be appreciated!
cmake_minimum_required(VERSION 2.6)
project(Lab_4)
add_library(Trip_4 Lab_4/Trip4.cpp)
add_executable(Lab_4 Lab_4/Lab_4.cpp)
target_link_libraries(Lab_4 Trip_4 ${EXTRA_LISTS})
Your exact intentions are not completely clear, but the above are the simplest possible instructions according to your current question description.
Are you absolutely sure your CMake is version 2.6? You should update the version to whatever CMake you are currently using (type cmake --version to find out).
To add your sources to CMake project, you can use the aux_source_directory command. If your sources are in Lab_4 folder, then you can do the following:
project(Lab_4)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/Lab_4 LAB4_SOURCES)
add_executable(Lab_4 ${LAB4_SOURCES})
The CMAKE_CURRENT_SOURCE_DIR is the path of the directory where the current CMakeFiles.txt is. The example above won't build Trip_4.cpp as a library but use it as another source file together with Lab_4.cpp.
If you wish to build the Trip_4.cpp as library fist I recommend to separate it from Lab_4.cpp to make later uses easier. An example directory structure could be:
MyProject/
|-- app/
| |-- src/
| | `-- Lab_4.cpp
| |-- inc/
| `-- CMakeLists.txt
|-- lib/
| |-- src/
| | `-- Trip_4.cpp
| |-- inc/
| `-- CMakeLists.txt
`-- CMakeLists.txt
In this case the MyProject/lib/CMakeLists.txt will contain something like the following:
project(Trip_4)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src TRIP4_SOURCES)
add_library(Trip_4 ${TRIP4_SOURCES})
The MyProject/app/CMakeLists.txt will be almost the same as I showed in my first example, except now it has to maintain its dependency on Trip_4 library:
project(Lab_4)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../lib
${CMAKE_CURRENT_SOURCE_DIR}/inc
)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src LAB4_SOURCES)
add_executable(Lab_4 ${LAB4_SOURCES})
add_dependencies(Lab_4 Trip_4)
target_link_libraries(Lab_4 Trip_4)
Finally, the MyProject/CMakeLists.txt has to tie together the library and the executable subprojects as follows:
project(MyProject)
add_subdirectory(lib)
add_subdirectory(app)
I have a directory layout like the following
projectA/
|-- CMakeLists.txt
|-- src/
|-- main.cpp
projectB/
|-- CMakeLists.txt
|-- src/
|-- file1.cpp
|-- file1.hpp
|-- file2.hpp
|-- main.cpp
|-- third_party/
|-- include
|-- lib1
I opened both project successfully in Qt Creator (using Ctrl+O and open the CMakeLists.txt file) and they're are able to build and run independently.
I need to gain access to file1.Xpp and file2.hpp from projectA. Is there a way in Qt Creator to add projectB as a subproject in projectA? And One might keep in mind that file1.Xpp and file2.hpp might depend on the third party library.
Using Ctrl+N -> Other Project -> Subdirs Project I can add a subproject, but only an empty one, if I'm not mistaken.
No, you can't add a CMake subject as a sub project.
Sub project is based of qmake.
Say I have a project that looks like:
Project (dir)
-- CMakeLists.txt
-- MyLib (dir)
|-- CMakeLists.txt
|-- MyLib.h
|-- MyLib.cpp
-- MyOtherLib (dir)
|-- CMakeLists.txt
|-- MyLib.h (note that this is exactly the same name as in MyLib above)
|-- MyLib.cpp
If in MyLib/CMakeLists.txt I do this:
target_include_directories(MyLib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
Then anything that target_link_libraries to MyLib will have the "correct" include path to do #include "MyLib.h". However, if another executable MyExecutable depends on both libraries using target_link_libraries(MyExecutable MyLib MyOtherLib) you'd like to be able to instead specify which one is intended with #include "MyLib/MyLib.h" or #include "MyOtherLib/MyLib.h". The only way I see to do that is to instead use:
target_include_directories(MyLib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
which kind of defeats one of the nice things about target_include_directories in that it really strongly enforces avoiding accidental header dependencies, because you literally can't include things that you aren't explicitly claiming to use.
Is there another way to get this #include "MyLib/MyLib.h" behavior?
You should reconsider your directory tree as follows:
Project (dir)
-- CMakeLists.txt
-- MyLib (dir)
|-- CMakeLists.txt
|-- src (dir)
MyLib.cpp
|-- include/MyLib (two dirs)
MyLib.h
-- MyOtherLib (dir)
|-- CMakeLists.txt
|-- src (dir)
MyLib.cpp
|-- include/MyOtherLib (two dirs)
MyLib.h
In this way you avoid including the ../, i.e. Project, folder and everything therein, which is not a clean approach and may lead to other problem should you add other files/folders in the future.
Then, you can write in MyLib/CMakeLists.txt
target_include_directories(MyLib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/include)
and in MyOtherLib/CMakeLists.txt
target_include_directories(MyOtherLib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/include)
As a result, you will be able to write #include "MyLib/MyLib.h" and #include "MyOtherLib/MyLib.h" in any program linking against the libraries in the build-tree.
If you also want to differentiate the include directories between the build-tree and the install-tree have a look at target_include_directories documentation and the useful cmake-generator-expressions.