Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake: Build Multiple Executables in one Project with Static Library

Tags:

c++

cmake

I'm working on a project that consists of 3 server executables and one library for shared code. I want it to be cross-platform, so I'm using CMake (since Xcode is being a pain anyway) to handle the build process. I'm having trouble with setting up the CMakeLists so that I can include the library from a directory at the same level when I'm building the executable.

Here's the directory structure (and the CMake files):

tethealla2.0/
    CMakeLists.txt
    libtethealla/
        CMakeLists.txt
        encryption/
        utils/
    patch_server/
        CMakeLists.txt
    login_server/
        CMakeLists.txt
    ship_server/
        CMakeLists.txt

My top-level CMake (tethealla2.0/CMakeLists.txt, only includes the sub-project that should compile):

project(tethealla CXX)
cmake_minimum_required(VERSION 2.6)

add_subdirectory(libtethealla)
add_subdirectory(patch_server)

tethealla2.0/libtethealla/CMakeLists.txt, which generates a static library:

project(Libtethealla C)
cmake_minimum_required(VERSION 2.6)

include_directories(encryption)

set(ENC_DR encryption/)

set(ENCRYPTION_SOURCES 
  ${ENC_DR}/psobb-crypt.c
  ${ENC_DR}/psogc-crypt.c
  ${ENC_DR}/psobb-crypt.c
  ${ENC_DR}/encryption.c
  )

add_library(tethealla STATIC ${ENCRYPTION_SOURCES})

tethealla2.0/patch_server/CMakeLists.txt thus far:

project(patch_server CXX)
cmake_minimum_required(VERSION 2.6)

add_executable(server main.cc)
target_link_libraries(server tethealla)

So it makes more sense if I build it from the top level since tethealla2.0/CMakeLists.txt will inherit the targets from each of the subdirectories and the one in patch_server will have access to the tethealla library. However what I want is to be able to build from within these subdirectories to generate Xcode projects so that I can work on/recompile them individually. To do so I need to be able to get to the libtethealla/build directory (where CMake outputs) to access the libtethealla.a library from patch_server. Is this possible?

On kind of another note, even in building from the top-level directory my source in patch_server can't include "encryption.h", the header file for the library in encryption. Which seems to be building fine. Any thoughts on that are also greatly appreciated!

like image 456
drodman Avatar asked May 15 '14 17:05

drodman


People also ask

What is the difference between CMake and Gmake?

make or gmake uses Makefile s to describe how to build your code. A Makefile contains targets and recipes. A target can be an object file or executable and the recipe is how to produce that target. cmake is a higher level language with the same purpose but with a higher level of abstraction.

Is CMake faster than make?

CMake does a two-step build: it generates a low-level build script in ninja or make or many other generators, and then you run it. All the shell script pieces that are normally piled into Makefile are only executed at the generation stage. Thus, CMake build can be orders of magnitude faster.

Does CMake create executable?

The most basic CMake project is an executable built from a single source code file. For simple projects like this, a CMakeLists. txt file with three commands is all that is required.


1 Answers

My solution is to use add_subdirectory with relative patch to shared_lib directory. I don't think that this is a perfect solution it has its caveats:

  • Logic very similar to a header guard must be added to library CMakeLists.txt to prevent from defining targets multiple times.
  • Each CMakeList.txt file must know the relative path to the library, if one want to move library all CMakeLists must be updated.

Let's assume that the directory structure looks like this:

root/
    CMakeLists.txt
    shared_lib/
        CMakeLists.txt
        inc/
            foo.h
        src/
            foo.c
    exec1/
       CMakeLists.txt
       main.c
    exec2/
       CMakeLists.txt
       main.c

root/CMakeList.txt

cmake_minimum_required(VERSION 2.6)

add_subdirectory(shared_lib)

add_subdirectory(exec1)
add_subdirectory(exec2)

I have decided that shared_lib/CMakeLists.txt will export a variable named SHARED_DIR_INCLUDE_DIR. This approach helps to decouple things a little bit.

root/exec1/CMakeLists.txt

cmake_minimum_required(VERSION 2.6)

add_subdirectory(./../shared_lib shared_lib)

include_directories(${SHARED_LIB_INCLUDE_DIR})

set(SRCS main.c)
add_executable(exec1 ${SRCS})
target_link_libraries(exec1 shared_lib)

if() in the fourth line solves the issue with target's multiple definition in case the CMakeLists file is added multiple times. The second and the third lines exports the include directory for library in SHARED_LIB_INCLUDE_DIR

root/shared_lib/CMakeLists.txt

cmake_minimum_required(VERSION 2.6)

set(SHARED_LIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/inc)

set(SHARED_LIB_INCLUDE_DIR ${SHARED_LIB_INCLUDE_DIR} PARENT_SCOPE)

if(TARGET shared_lib)

message("shared_lib is already defined")

else()

include_directories(${SHARED_LIB_INCLUDE_DIR})

set(LIB_SRCS ./src/foo.c)

add_library(shared_lib STATIC ${LIB_SRCS})

endif()
like image 154
luantkow Avatar answered Oct 11 '22 17:10

luantkow