CMake creating libraries that depend each other - c++

my goal is to create libraries like client and generator and use them in src/main.cpp, but sometimes these libraries depend each other.
In this case: client/User.hpp uses generator/IdGenerator.hpp
Project
│
├── CMakeLists.txt
├── libs
│   ├── CMakeLists.txt
│   ├── client
│   │   ├── CMakeLists.txt
│   │   ├── User.cpp
│   │   └── User.hpp
│   └── generator
│   ├── CMakeLists.txt
│   ├── IdGenerator.cpp
│   ├── IdGenerator.hpp
│   └── Types.hpp
└── src
└── main.cpp
Project/CMakeLists.txt:
cmake_minimum_required (VERSION 3.8)
project(game-project VERSION 0.1.0)
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_FLAGS "-Wall -Wextra -O0 -std=c++20")
add_executable (game src/main.cpp)
add_subdirectory(libs)
target_link_libraries(game libclient libgenerator)
libs/CMakeLists.txt:
add_subdirectory(generator)
add_subdirectory(client)
libs/client/CMakeLists.txt:
add_library(libclient STATIC
User.cpp
User.hpp
)
include_directories(generator/)
target_link_libraries(libclient libgenerator)
libs/generator/CMakeLists.txt:
add_library(libgenerator STATIC
IdGenerator.cpp
IdGenerator.hpp
Types.hpp
)
C++ files:
main.cpp:
#include <client/User.hpp>
int main(int argc, const char* argv[])
{
User user;
return 0;
}
client/User.hpp:
#pragma once
#include <generator/IdGenerator.hpp>
class User
{
Identifier id = IdGenerator::generateId();
};
When I run make after cmake, I get this error:
In file included from Project/libs/client/User.cpp:1:
Project/libs/client/User.hpp:3:10: fatal error: generator/IdGenerator.hpp: No such file or directory
3 | #include <generator/IdGenerator.hpp>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Sorry for the verbose summary, I was able to shorten the example this much. What do you think the problem is?
This question might seem like a duplicate of CMake libraries that depend on each other but as you can see I'm already applying the
include_directories(generator/).

I misunderstood what the problem was initially, but now I think this might help.
Try adding to the CMakeLists.txt of your client instead of
include_directories(generator/)
this command
target_include_directories(libclient PUBLIC <Path to your generator file>)
Maybe you need to experiment a little to get the path correct as you might need to either specify it from the root directory or the current one (where this CMakeLists.txt resides), but it might solve your problem.

Related

Decrease the length of headers with help of target_include_directories

I have a project
├── CMakeLists.txt
│   ├── log
│   │   ├── CMakeLists.txt
│   │   ├── include
│   │   │   ├── log.h
│   │   └── src
│   │   ├── log.cpp
│   └── main.cpp
In log.cpp I am usng #include "../include/log.h" and in main.cpp I amd using #include "include/log.h"
I want to use #include "log.h"
I read that target_include_directories can help me.
How can I apply it to my CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(Logger)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#include_directories(log/include/) -- I used this, but I want to use target_include_directories
add_library(log_lib log/src/log.cpp)
add_executable(demo main.cpp)
target_link_libraries(demo log_lib)
define the target and then use the name as the first argument for target_include_directories
add_library(log_lib log/src/log.cpp)
target_include_directories(log_lib PUBLIC log/include)
worry about INTERFACE vs PUBLIC vs PRIVATE after you've got it all working and you want to understand it better. (This option transitively affects targets that depend on your library).
The line below helped
target_include_directories(log_lib PUBLIC log/include)

CMake include library in another library

I have a given project structure
.
├── CMakeLists.txt
├── lib
│   ├── lodepng
│   │   ├── CMakeLists.txt
│   │   └── src
│   │   ├── lodepng.cpp
│   │   └── lodepng.h
│   └── pixel_reader
│   ├── CMakeLists.txt
│   └── src
│   ├── hello.cpp
│   └── hello.h
├── main.cpp
With the following CMakeLists
./CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(pov_system VERSION 1.0)
add_subdirectory(lib/lodepng)
add_subdirectory(lib/pixel_reader)
add_executable(pov_system main.cpp)
target_link_libraries(pixel_reader PRIVATE lodepng)
target_link_libraries(pov_system PRIVATE pixel_reader)
./lodepng/CMakeLists.txt
add_library(
lodepng
src/lodepng.cpp
src/lodepng.h
)
target_include_directories(lodepng PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
./pixel_reader/CMakeLists.txt
add_library(
pixel_reader SHARED
src/hello.cpp
src/hello.h
)
target_include_directories(pixel_reader PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
As one can see, I try to link the 'lodepng' library to the 'pixel_reader' library and include the 'lodepng.h' to the 'hello.h' file.
But at the moment I get the following error while trying to build the project.
[build] <path-to-project>/pov_system/lib/pixel_reader/src/hello.h:2:10: fatal error: lodepng.h: No such file or directory
[build] 2 | #include "lodepng.h"
[build] | ^~~~~~~~~~~
[build] compilation terminated.
Question
Why is my code not finding the 'lodepng.h' file or (and even more important) is it a good practice to link from one library to another?
Maybe two really simple questions, but just started to dive into the world of CMake, Compiling, etc... and I really appreciate your help.
Why is my code not finding the 'lodepng.h' file or (and even more important)
Because you probably didn't give it correct path. One way to fix that would be to give the exact path in hello.h
#include "../../lodepng/src/lodepng.h
Second way is to use target_include_directories:
target_include_directories(pixel_reader PUBLIC "../../lodepng/src/")
is it a good practice to link from one library to another?
It depends on your project. If library A requires library B, then yes, it is okay in my opinion.
More importantly, you are creating the target in the wrong place i.e., in the root CMakeLists file. It must be done in the directory in which target is created.
./pixel_reader/CMakeLists.txt
# create target
add_library(
pixel_reader SHARED
src/hello.cpp
src/hello.h
)
target_link_libraries(pixel_reader PRIVATE lodepng) #link library where target is created
target_include_directories(pixel_reader PUBLIC "../../lodepng/src/")
target_include_directories(pixel_reader PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
Your pixel_reader library target possibly needs lodepng.h header to compile, because it depends on it.
something like
target_include_directories(pixel_reader PUBLIC "PATH_TO_LODE_PNG_HEADER_DIRECTORY")
could solve this problem.

cmake target_link_libraries() cannot find renamed lib target by set_target_properties(archive_output_name)

RT~ ps: cmake version 3.9.2
My codebase just like this.
suzanwen#n224-004-133:~/repos/C++/ttt:)$ tree -L 2
.
├── build
│   ├── bin
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── lib
│   ├── Makefile
│   ├── test
│   └── thirdparty
├── build.sh
├── CMakeLists.txt
├── Makefile
├── test
│   ├── CMakeLists.txt
│   └── main.cc
└── thirdparty
├── CMakeLists.txt
├── gflags
└── hellolib
10 directories, 9 files
my thirdparty/hellolib/CMakeLists.txt is
PROJECT(hello)
SET(LIBHELLO_SRC hello.cc)
MESSAGE(STATUS "LIBRARY PATH=" ${LIBRARY_OUTPUT_PATH})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello_static PROPERTIES ARCHIVE_OUTPUT_NAME "hello")
my test/CMakeLists.txt is
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/thirdparty/hellolib
${PROJECT_SOURCE_DIR}/thirdparty/gflags/include)
IF(LIBRARY_OUTPUT_PATH)
LINK_DIRECTORIES(${LIBRARY_OUTPUT_PATH})
ENDIF(LIBRARY_OUTPUT_PATH)
ADD_EXECUTABLE(main main.cc)
TARGET_LINK_LIBRARIES(main hello)
# TARGET_LINK_LIBRARIES(main hello_static)
when I build my top-level project, an error occurs like this.
/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cc.o -o ../bin/main -L/home/suzanwen/repos/C++/ttt/build/lib -Wl,-rpath,/home/suzanwen/repos/C++/ttt/build/lib -lhello
/usr/bin/ld: cannot find -lhello
But when I comment the line # SET_TARGET_PROPERTIES(hello_static PROPERTIES ARCHIVE_OUTPUT_NAME "hello") and TARGET_LINK_LIBRARIES with hello_static, everything goes fine.
It seems that TARGET_LINK_LIBRARIES cannot find renamed lib target. Could anyone explain it? thanks in advance.
It seems that TARGET_LINK_LIBRARIES cannot find renamed lib target.
Setting ARCHIVE_OUTPUT_NAME property renames not a target, but an output file. So linking with a target still works:
TARGET_LINK_LIBRARIES(main hello_static)
One cannot rename the target once it is created, but it is possible to create ALIAS for a target:
ADD_LIBRARY(hello ALIAS hello_static)
After that it is possible to link with the alias:
TARGET_LINK_LIBRARIES(main hello)

Error trying to compile a C++ program that uses a shared library

I'm trying to compile an example program that uses a shared library (also developed by me) in C++, which name is libtestlib.so.
The error
I have compiled the shared library without problems, but when I try to compile an executable that uses this library, I have the following error: iface/libtestlib.so: undefined reference to 'ALIB::function()'
What I have done
I have done the following:
C++ library (files in $project_dir/lib1):
// HEADER
#ifndef ALIB_H
#define ALIB_H
namespace ALIB{
int function();
}
#endif
-------------------------------------------
// SOURCE
#include "alib.h"
using namespace ALIB;
int ALIB::function(){
return 101;
}
The C interface for the C++ library (files in $project_dir/iface)
// HEADER
#ifndef IFACE_H
#define IFACE_H
#include "alib.h"
extern "C"{
int IFACE_function();
}
#endif
--------------------------------
// SOURCE
#include "iface.h"
int IFACE_function(){
return ALIB::function();
}
--------------------------------------------------------
// CMakeLists used to build the library:
cmake_minimum_required(VERSION 2.8)
PROJECT( testlib )
include_directories( ../lib1 )
add_library( testlib SHARED iface.cpp )
The executable that uses the library (files in $project_dir/main):
// SOURCE
#include "iface.h"
#include <iostream>
using namespace std;
int main(){
cout << IFACE_function() << endl;
}
-------------------------------------
// CMakeLists used to build the executable (file in `$project_dir`):
cmake_minimum_required(VERSION 2.8)
PROJECT( testlib )
find_library( LIB NAMES testlib PATHS ./iface )
include_directories( ./lib1 ./iface )
add_executable( testlib ./main/main.cpp )
target_link_libraries( testlib ${LIB} )
Generated files
$project_dir:
all generated by cmake. (CmakeLists.txt, CMakeCache, cmake_install.cmake, MakeFile)
$project_dir/lib1:
alib.cpp and alib.h
$project_dir/iface:
iface.cpp, iface.h, libtestlib.so and all generated by cmake.
$project_dir/main:
main.cpp.
As tree:
$project_dir
├── CMakeCache.txt
├── CMakeFiles
│   ├── ...
├── cmake_install.cmake
├── CMakeLists.txt
├── CMakeLists.txt~
├── iface
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── ...
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── CMakeLists.txt~
│   ├── iface.cpp
│   ├── iface.h
│   ├── libtestlib.so
│   └── Makefile
├── lib1
│   ├── alib.cpp
│   └── alib.h
├── main
│   └── main.cpp
└── Makefile
Thanks to Yuan's comment I have found the problem. I needed to add the alib.cpp file to the CMakeLists.txt, this way:
// CMakeLists used to build the library:
cmake_minimum_required(VERSION 2.8)
PROJECT( testlib )
include_directories( ../lib1 )
add_library( testlib SHARED iface.cpp ../lib1/alib.cpp )

CMake 'no rule to make target' with external library

I am trying link one of my programs to libevent. I am using CMake as build system. My project structure is as follows:
my_project
├── CMakeLists.txt
├── README.md
├── build
│  └── Build stuff
└── software
├── README.md
├── CMakeLists.txt
├── include
├── libraries
│   ├── libevent
│ │   └── CMakeLists.txt
│   └── anotherlibrary
│      └── CMakeLists.txt
├── prog1
│   ├── CMakeLists.txt
├── prog2
│   ├── CMakeLists.txt
└── prog3
└── CMakeLists.txt
CMakeList.txt of prog1 (the one that's needs to be linked to libevent)
cmake_minimum_required(VERSION 2.6)
project (prog1)
file(GLOB prog1
"*.h"
"*.cpp"
)
include_directories("${PROJECT_INCLUDE_DIR}/libevent/include")
add_executable(${PROJECT_NAME} ${prog1})
target_link_libraries(${PROJECT_NAME} event_core)
But when I build the project make can't find the library build by libevent. it searched for: libraries/libevent/lib/libevent_core.a this is the wrong path since libevent builds it libs inside: my_project/build/software/libraries/libevent/lib/libevent_core.a
How do I tell CMake to search there for the library? I already added the following lines to my Cmake file but this wasn't working
link_directories(/my_project/build/software/libraries/libevent/lib/)
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/lib)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/bin)
Anyone a suggestion?
I fixed the problem myself by removing the content from the build directory and re running cmake .. inside the build directory.
I think CMake was somehow not aware of the changes I made and by rebuilding the project the problem was fixed.