Compiling and linking subproject library with CMake - compilation

I have 2 projects (prj1 and prj2). One (prj2) depends on the other (prj1) that is a static library. I arrive to compile them separately with CMake.
But I needed to integrate one (prj1) to the other one (prj2). So I would like CMake to compile the static library (prj1) before the other (prj2) and then link the static library. I tried things, but id did not work.
prj1 "core" is https://gitlab.com/RyDroid/PlanetWars2dRT-core
prj2 "SDL2" is https://gitlab.com/RyDroid/PlanetWars2dRT-SDL2/ (see branch adding-core)
In prj2, externals/core is a git submodule (for non git users, you can see this directory as a copy-paste of prj1).
I tried (without success) this CMakeLists.txt in prj2 "SDL2":
cmake_minimum_required(VERSION 2.8)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wformat=2 -Wpedantic -D_FORTIFY_SOURCE=2")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# TODO
endif()
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
# if (CMAKE_VERSION VERSION_LESS "3.1")
# if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR
# CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# set (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
# endif()
# else()
# set(CMAKE_CXX_STANDARD 11)
# endif()
project(PlanetWars2dRT-SDL2)
# Version number
set(VERSION_MAJOR "0")
set(VERSION_MINOR "0")
set(VERSION_MICRO "0")
# Configure a header file to pass some of the CMake settings
# to the source code.
configure_file (
"src/compilation_config.h.in"
"${PROJECT_BINARY_DIR}/compilation_config.h"
)
# Add the binary tree to the search path for include files
# so that we will find compilation_config.h
include_directories("${PROJECT_BINARY_DIR}")
set(LIBRARY_OUTPUT_PATH lib/${CMAKE_BUILD_TYPE})
set(EXECUTABLE_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE})
include_directories(src/)
file(
GLOB_RECURSE
source_files
src/*
)
add_executable(planet-wars-2d-rt-sdl2 ${source_files})
#include(ExternalProject)
#ExternalProject_Add(PlanetWars2dRT PREFIX externals/core/)
include_directories(externals/core/src/utils/ externals/core/src/specific/)
add_subdirectory(externals/core/)
#find_package(PlanetWars2dRT-core REQUIRED)
include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)
pkg_search_module(SDL2GFX REQUIRED SDL2_gfx)
include_directories(${SDL2_INCLUDE_DIRS} ${SDL2IMAGE_INCLUDE_DIRS})
target_link_libraries(
planet-wars-2d-rt-sdl2
planet-wars-2d-rt-core
${SDL2_LIBRARIES} ${SDL2GFX_LIBRARIES}
)
That is a simplified version of the tree of prj2:
.
├── build (with CMake stuff generated with "cmake ..")
├── CMakeLists.txt
├── externals
│   └── core
│ ├── build (with CMake stuff generated with "cmake ..")
│   ├── CMakeLists.txt
│   ├── makefile
│   └── src
├── makefile
├── README.md
└── src
    ├── compilation_config.h.in
   └── planet-wars-2d-rt-sdl2.cpp
How can I compile the library of prj1 "core" in prj2 "SDL2" with CMake, and then link the library of prj1 with prj2 (again with CMake)?
If your solution does not work with a non GNU/Linux OS, it is not a big problem. Note: my PC is running on Debian GNU/Linux 8 "Jessie".
Regards.

I cannot access your repo https://gitlab.com/RyDroid/PlanetWars2dRT-SDL2/, perhaps the servers are down for maintenance. If I understand your problem correctly, you may create a structure like that:
root/
CMakeLists.txt // 1
src/
CMakeLists.txt // 2
main.cpp
SDL2/
some sources
CMakeLists.txt // 3
core/
some sources
CMakeLists.txt // 4
In the CMakeLists.txt [1] you should declare your project name, required packages, common flags, include paths etc.:
cmake_minimum_required( VERSION 2.x )
project(name)
include_directories(inc inc/core inc/SDL2 inc/SthElse)
add_subdirectory(src)
In CMakeLists.txt [2] for subdir src you should declare your main executable and also add subdirs with your prj1 and prj2
add_subdirectory(core)
add_subdirectory(SDL2)
add_executable(main main.cpp)
target_link_libraries(main core SDL2 SomeOtherLib)
Finally, in your CMakeLists.txt [3] && [4] in your lib dirs you should declare static libraries:
add_library(core STATIC ${YourSourceFiles})
This approach always worked for me. If you used to compile and run "core" and "SDL2" as standalone binaries, perhaps you will have to reorganize them a little bit.

Both project have a file "compilation_config.h". At compilation time, the wrong was taken so compilation failed, because the code used was #include "compilation_config.h" that was ambigous.
So I created a "include/project-name" dir in both project and I changed the include path : "prj1/compilation_config.h" or "prj2/compilation_config.h". Thanks to that there was no ambiguity anymore, so it works now!

Related

How to Define Output Directory of Coverage Files in CMake

I am trying to make a very simple regression model that (among other things), builds and compiles a GCC target for coverage, executes, and then publishes a standard Cobertura coverage report (all within Jenkins). The Jenkins part is somewhat irrelevant here, I'm only concerned with CMake syntax at the moment. This is my CMake file so far:
cmake_minimum_required( VERSION 3.15 )
# Project's name
project( my_project )
# Set the output folder where your program will be created
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/test/bin)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set( CMAKE_VERBOSE_MAKEFILE on )
# Generate coverage on GCC.
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
set(LDFLAGS "${LDFLAGS} -lgcov -fprofile-arcs")
endif()
# Includes and Sources
include_directories(${PROJECT_SOURCE_DIR}/inc)
file(GLOB APP_SRC "./src/*.c")
file(GLOB TEST_DEPENDS_SRC "./test/src/*.c")
# Add executable to list.
add_executable( ${PROJECT_NAME}_Test ${APP_SRC} ${TEST_DEPENDS_SRC} )
This generates my *.gcno and *.gcda files in the directory /test/build/gcc/CMakeFiles/my_project.dir/*, but for ease of post-processing, I think I want these files placed alongside their source. Is that possible? If so, how? Is that best practice? I'm still pretty green when it comes to CMake.

CMake MFC project in Visual Studio missing resource editor

I'm having a hard time opening the interactive resource editor in a MFC CMake project that otherwise compiles and runs just fine.
The project files are laid out as follows:
.
├── CMakeLists.txt
├── inc
│   ├── <...>
│   ├── resource.h
├── res
│   ├── MyApp.ico
│   ├── MyApp.rc
│   └── MyApp.rc2
└── src
   ├── CMakeLists.txt
   └── <...>
Top CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(MyProject)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 14)
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /we4715") # makes missing return as error
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") # parallel build
endif()
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/output)
# MFC
add_definitions(-D_AFXDLL)
set(CMAKE_MFC_FLAG 1)
add_subdirectory(src)
src CMakeLists.txt:
include_directories(${CMAKE_SOURCE_DIR}/inc)
include_directories(${CMAKE_SOURCE_DIR}/res)
include_directories(${CMAKE_SOURCE_DIR})
set(SOURCES
<...>
)
set(HEADERS
<...>
)
add_executable(
${PROJECT_NAME}
WIN32
${SOURCES}
${HEADERS}
${CMAKE_SOURCE_DIR}/res/MyApp.rc
${CMAKE_SOURCE_DIR}/res/MyApp.rc2
)
install(TARGETS MyApp
RUNTIME DESTINATION .)
In Visual Studio (Pro) the project loads just fine and compiles for every configuration I need, but if I try to open an .rc file I get errors on missing headers from MFC and ATL (afxres.h, winres.h, dde.rh, ...). The resource file won't open in the resource editor like it does on a VS solution.
The mssage happens when double-clicking on MyApp.rc, and I get
fatal error RC1015: cannot open include file 'afxres.h'.
I use the latest VS version available as of today which is 15.8.5, and this happens when opening the CMake project in Visual Studio.
I have already installed the ATL/MFC components in my Visual Studio installation. Like I said, it compiles just fine so dependencies are resolved correctly.
Am I missing something? Is this even possible?

Can't build with Cmake

I am new to Cmake and I am trying to create a CMakeLists.txt to build my project. I can build my project from command line using g++ compiler but when it comes to Cmake I am confused.
The directory structure is like this :
Project_folder
|--> Source
|--> main.cpp
|--> file1.cpp
|--> file2.cpp
|--> Header
|--> header1.h
|--> header2.h
|--> build (from where I run cmake .. and make)
CMakeLists.txt (this is under Project_folder)
Dependencies
|--> utils
|--> Utils.cpp
|--> include (has many folders in here)
|--> build (this path is in LD_LIBRARY_PATH as well)
|--> sharedlib1.so
|--> sharedlib2.so
Now from within the Project_Folder I can successfully run :
g++ ./Source/main.cpp ./Source/file1.cpp ./Source/file2.cpp ../Dependencies/utils/Utils.cpp -I ../Dependencies -I ../Dependencies/include/ -I ./Header/ -L ../Dependencies/build -std=c++11 -lsharedlib1 -lsharedlib2 -o ./build/main `pkg-config opencv --cflags --libs`
and generate the executable file.
Now I want to configure a CMakeLists.txt and try to replicate what the above compiler line is doing but with no success (I can cmake .., but I cannot make). CMakeLists.txt looks like this :
cmake_minimum_required(VERSION 2.8.9)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
project(my_project)
#For the shared library:
set ( PROJECT_LINK_LIBS sharedlib1.so sharedlib2.so)
link_directories(${PROJECT_SOURCE_DIR}/../Dependencies/build/ )
include_directories(${PROJECT_SOURCE_DIR}/../Dependencies ${PROJECT_SOURCE_DIR}/../Dependencies/include ${PROJECT_SOURCE_DIR}/Header)
file(GLOB SOURCES "Source/*.cpp" )
set(CMAKE_CXX_FLAGS_RELEASE pkg-config opencv cflags libs)
## add_executable(name_of_output.o list_of_cpp_files)
add_executable(build ${SOURCES})
Running make after generating the makefile I get undefined reference to everything inside main.cpp. Is there anything obvious in the CMakeLists.txt that I should change?
Your call to g++ includes the ../Dependencies/utils/Utils.cpp file, but your call to add_executable is only using the files matched by Source/*.cpp. A quick solution would be to add ../Dependencies/Utils.cpp to the call to add_executable() making it
add_executable(build ${SOURCES} "${PROJECT_SOURCE_DIR}/../Dependencies/Utils.cpp")
On a related note: CMake discourages using file(GLOB ...) to get a list of source files, it's generally better to list the source files explicitly
You should use target_link_libraries after add_executable.
Please check the examples:
Executable with Static Library
Executable with Shared Library
While running the application you will also get some errors. Please be aware of RPATH.
Ok I managed to solve it ! :)
# set Cmake minimum version to use
cmake_minimum_required(VERSION 2.8.9)
# set the compiler
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# name your project
project(my_project)
set(CMAKE_BUILD_TYPE Release)
# Find and load the settings from the packages
find_package(PkgConfig REQUIRED)
find_package(OpenCV REQUIRED )
# set the extra flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -cflags -libs")
# set the shared libraries name (where the libraries are libsharedlib1.so and libsharedlib2.so + opencv runtime libraries)
set(PROJECT_LINK_LIBS sharedlib1 sharedlib2) ${OpenCV_LIBS}
# include the header files (.h)
include_directories(${PROJECT_SOURCE_DIR}/../Dependencies ${PROJECT_SOURCE_DIR}/../Dependencies/include ${PROJECT_SOURCE_DIR}/Header)
# add the source files (.cpp) using the set command as follow
set(SOURCES
Source/main.cpp
Source/file1.cpp
Source/file2.cpp
${PROJECT_SOURCE_DIR}/../Dependencies/utils/Utils.cpp)
# link the shared libraries (/build/libsharedlib1.so and /build/libsharedlib2.so)
link_directories(${PROJECT_SOURCE_DIR}/../Dependencies/build/)
# add_executable(name_of_output list_of_cpp_files)
add_executable(main ${SOURCES})
# link the executable with the shared libraries
target_link_libraries(main ${PROJECT_LINK_LIBS} )
and finally ./main will run the program !

FFmpeg on Android with Rubberband

When I try to link librubberband.a I get:
libavfilter/af_rubberband.c:236: error: undefined reference to 'rubberband_set_pitch_scale'
I compiled rubberband for armv7a, and created a static library (rubberband.a).
I checked the library, and It contained the needed symbols (using nm).
I verified that librubberband.a is in the libpath (-L)
I verified that extern C exists in the rubberband.c.h file.
Any ideas?
The error happened in the link stage. Make sure the link directory has been added to -L parameters of your compiler.
-L/directory/of/your/lib
And specify the library with -l option.
So make sure the option -L/directory/of/your/lib -lrubberband set for your compiler when you build ffmpeg with rubberband support.
If you didn't use pkg-config to add the library. You can use the option --extra-ldflags to add when configure ffmpeg before build.
./configure \
# some configure options
--extra-ldflags="-L/directory/of/your/lib -lrubberband" \
# more configure options
If you use pkg-config to find out the libraries. Just add the library.pc directory to PKG_CONFIG_PATH, and let the build system do the remaining.
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/directory/to/your/rubberband.pc
Updated
Finally make sure you link against to the same architecture of your library.
$ arm-linux-androideabi-readelf -h librubberband.a |grep 'Class\|Machine
For armeabi-v7a, it should be ELF32 and ARM.
Updated
I have cloned the source of rubberband from https://bitbucket.org/breakfastquay/rubberband
And found the function call rubberband_set_pitch_scale is defined at src/rubberband-c.cpp, this file is not include in Android.mk when build for Android (WHY?).
So you have to add this file to build.
RUBBERBAND_SRC_FILES = ... \
$(RUBBERBAND_SRC_PATH)/rubberband-c.cpp
After build done, you need to create directory structure like below
.
├── include
│   └── rubberband
│   ├── RubberBandStretcher.h
│   └── rubberband-c.h
└── lib
├── librubberband.a
└── pkgconfig
└── rubberband.pc
The file rubberband.pc was copied from rubberband.in.pc with some minor changes.
prefix=/path/to/rubberband/install/root
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: rubberband
Version: 1.8.1
Description:
Libs: -L${libdir} -lrubberband -L/path/to/android/ndk/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a -lgnustl_static
Cflags: -I${includedir}
Then add
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/path/to/rubberband/install/root
before ./configure to tell ffmpeg find rubberband by pkg-config.
I have tried with the latest ffmpeg, it works.

Cmake Shared library

I am learning CMake but I am struggling to understand how to link a binary file to a shared library and then install these files in a release folder.
These is the structure of my project:
├── CMakeLists.txt
├── build
├── main
│   ├── CMakeLists.txt
│   └── main.cpp
├── release
|_______bin
│   ├── include
│   │   └── math.h
│   └── lib
│   └── libmathLib.dylib
└── shared_lib
├── CMakeLists.txt
├── include
│   └── math.h
└── src
└── math.cpp
In the root CMakeLists.txt I've defined the project settings and the subdirectory.
Root CMakeLists.txt:
cmake_minimum_required(VERSION 3.1)
project (Math)
set(CMAKE_BUILD_TYPE Release)
set(MAKE_INCLUDE_CURRENT_DIR ON)
ADD_SUBDIRECTORY(shared_lib)
ADD_SUBDIRECTORY(main)
Main CMakeLists.txt:
add_executable(main main.cpp)
TARGET_LINK_LIBRARIES(main LINK_PUBLIC mathLib)
Math lib ( shared lib )
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(mathLib SHARED src/math.cpp)
install(TARGETS mathLib DESTINATION /Users/giuseppe/development/cmake/release/lib LIBRARY NAMELINK_ONLY)
install(FILES include/math.h DESTINATION /Users/giuseppe/development/cmake/release/include)
When I build the project with Make, it doesn't link main.o to the shared library. Error :
Scanning dependencies of target mathLib
[ 50%] Building CXX object shared_lib/CMakeFiles/mathLib.dir/src/math.cpp.o
Linking CXX shared library libmathLib.dylib
[ 50%] Built target mathLib
Scanning dependencies of target main
[100%] Building CXX object main/CMakeFiles/main.dir/main.cpp.o
/Users/giuseppe/development/cmake/main/main.cpp:8:12: error: use of undeclared identifier 'sum'
count << sum(5,6) << endl;
^
1 error generated.
make[2]: *** [main/CMakeFiles/main.dir/main.cpp.o] Error 1
make[1]: *** [main/CMakeFiles/main.dir/all] Error 2
make: *** [all] Error 2
Release phase:
How can I make sure that the builds in the bin folder within the release folder use the shared lib in 'path/release/lib'? Possibly using a relative path such as '../lib/' ?
You must add include directory for library to main/CMakeLists.txt. Adding it to shared_lib/CMakeLists.txt is not enough. Try this line:
include_directories("../shared_lib/include")

Resources