Cmake Shared library - makefile

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")

Related

Include path relative to Makefile regarding assembler (GAS) files

Let's say I've got the following project structure:
<ASM_Project>/
├── <src>/
│ └── <boot>/
│ ├── boot.s
│ └── functions.s
└── Makefile
boot.s:
_start:
jmp testing
.include "src/boot/functions.s"
testing:
Makefile:
src/boot/boot.o: src/boot/boot.s src/boot/functions.s
as -o $# $<
boot.s and functions.s are in the same folder and yet .include "functions" doesn't seem to work in this case:
Ernie#Sanderson:~/ASM_Project$ make
as -o src/boot/boot.o src/boot/boot.s
src/boot/boot.s: Assembler messages:
src/boot/boot.s:11: Error: can't open functions.s for reading: No such file or directory
make: *** [Makefile:23: src/boot/boot.o] Error 1
Is there a way to pull it off though?

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?

Compiling and linking subproject library with CMake

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!

CMake and correct add shared library

I'm trying to add a shared library to my project using CMake. The library is MsgPack for C++11. I must be doing something wrong because none of the examples here compile. I get this error:
error: no match for ‘operator<<’ (operand types are
‘MsgPack::Serializer’ and ‘std::unique_ptr’)
serializer << MsgPack__Factory(Array(std::move(arrayWith3Elements)));
My guess is that it has to do with my CMake syntax. The file system tree where I keep the compiled library looks like this:
/home/I/direcytory/MsgPack/
├── include
│   ├── Container.h
│   ├── ContainerHeader.h
│   ├── Core.h
│   ├── Data.h
│   ├── Element.h
│   ├── Header.h
│   ├── MsgPack.h
│   ├── MsgPackSocket.h
│   ├── netLink.h
│   ├── Number.h
│   ├── Primitive.h
│   ├── Socket.h
│   ├── StreamManager.h
│   └── Utf8.h
├── libnetLink.a
└── libnetLink.so
In CMake I'm doing this:
cmake_minimum_required(VERSION 3.0.2)
project(MyProject)
add_library(libnetLink SHARED IMPORTED)
SET_PROPERTY(TARGET libnetLink PROPERTY IMPORTED_LOCATION /home/I/Direcytory/MsgPack/libnetLink.so)
set(SOURCE_FILES main.cpp)
include_directories("/home/I/Direcytory/MsgPack/include")
target_link_libraries(MyProject libnetLink)
CMake doesn't report any errors, but my program won't compile.
It's worth noting, the above method has worked fine for me with other libraries. That's what has me confused.

SCons env.Install("path_to_folder") does not show folder files in dependency tree

In SCons when a folder is installed the dependency tree is not aware of the contents of the folder. This means that implicit relationships cannot be created.
env.Install("out/bin","path/to/folder")
env.Install("out/archive", Glob("out/bin/folder/library.lib"))
In this sample code the Glob returns [] because SCons is unaware the folder contains a file called library.lib.
The only workaround I've found for this is to walk the directory and install each individual file.
Does the SCons Install not have an option to do this for you?
I have run into this as well. I have not found any other solution than to walk the directories as you describe. Though the contents of the folder are copied, to SCons there is just one target, and just one source, unless you specify each one individually.
import os
def recursive_install(target, source, env):
source_dirname = os.path.dirname(source)
for root, dirnames, filenames in os.walk(source):
for filename in filenames:
env.Install(os.path.join(
target, os.path.relpath(root, os.path.dirname(source))),
os.path.join(root, filename))
env = Environment()
recursive_install("out/bin", "path/to/folder", env)
env.Install("out/archive", "out/bin/folder/library.lib")
Which when run produces...
>> scons --version
SCons by Steven Knight et al.:
script: v2.3.4, 2014/09/27 12:51:43, by garyo on lubuntu
engine: v2.3.4, 2014/09/27 12:51:43, by garyo on lubuntu
engine path: ['/usr/lib/scons/SCons']
Copyright (c) 2001 - 2014 The SCons Foundation
>> tree
.
├── path
│   └── to
│   └── folder
│   └── library.lib
└── SConstruct
3 directories, 2 files
>> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
Install file: "path/to/folder/library.lib" as "out/bin/folder/library.lib"
Install file: "out/bin/folder/library.lib" as "out/archive/library.lib"
scons: done building targets.
>> tree
.
├── out
│   ├── archive
│   │   └── library.lib
│   └── bin
│   └── folder
│   └── library.lib
├── path
│   └── to
│   └── folder
│   └── library.lib
└── SConstruct
7 directories, 4 files
SCons doesn't have an option for recursively installing all files under a top-folder, because that's considered to be a rare case (note, how SCons prefers in-source-tree builds, such that you'd have to exclude a lot of files from the Install call otherwise). If you are creating the "files to install" within the same build, the preferred method would be to use the emitted list of targets from your Builder, and put it as second argument to the Install method:
mylibs = env.AnyBuilder('library', sources)
env.Install("out/bin", mylibs)
Then you don't have to manually list all the target files again with a recursive os.walk as in Kenneth's answer.

Resources