CMake Project Structure: How do I properly merge libraries together and include them in multiple executables
Asked Answered
R

1

2

I am building a C Project and I'm currently a little lost on how to properly link in the libraries.

To summarize: I will have 3 projects that will have multiple executables. The projects will be using code from a library that will have multiple directories (sub-libraries). I have all the includes for the project in an includes directory. And I also will have a testing directory for the src and the lib as well.

How do I link in a library thats in a separate directory?

Is there a way to I can merge all these libraries into one main library, so I only have to link a single library?

The structure looks like this:

Project:
   |-- bin   
   |-- build   
   |-- src     
   |   |-- Project 1   
   |   |      |-- Project1a.c
   |   |      |-- Project1b.c
   |   |      |-- cmakelists.txt
   |   |-- Project 2
   |   |      |--Project2.c
   |   |-- Project 3
   |   |      |--Project3.c
   |   |-- cmakelists.txt
   |
   |-- lib 
   |    |--Crypto_Lib
   |    |      |-- Crypto.c
   |    |      |-- cmakelists.txt
   |    |--Communications_Lib
   |    |      |-- Communications.c
   |    |      |-- cmakelists.txt
   |    |--Error_Lib
   |    |      |-- Error.c
   |    |      |-- cmakelists.txt
   |    |--cmakelists.txt
   |
   |-- include
   |    |--src
   |    |   |-- Project 1
   |    |   |     |-- Project1a.h
   |    |   |     |-- Project1b.h
   |    |   |-- Project 2
   |    |   |     |-- Project2.h
   |    |   |-- Project 3
   |    |         |-- Project3.h    
   |    |--lib
   |    |  |--Hash 
   |    |  |    |-- Crypto.h
   |    |  |--Communications
   |    |  |    |-- Communications.h
   |    |  |--Error
   |    |  |    |-- Error.h
   |
   |-- test
   |    |--src (etc...)
   |    |--lib (etc...)
   |    |--cmakelists.txt
   |
   |--cmakelists.txt

CMAKES I currently have:

~/CMakeLists.txt

    add_subdirectory(lib)
    add_subdirectory(src)
    add_subdirectory(test)

~/lib/CMakeLists.txt

    #To access the header file
    include_directories(${CMAKE_SOURCE_DIR}/includes/lib)   

    add_subdirectory(communications)
    add_subdirectory(crypto)
    add_subdirectory(error)

~/src/CMakeLists.txt

    #To access the header file
    include_directories(${CMAKE_SOURCE_DIR}/includes/src)   

    add_subdirectory(project_one)
    add_subdirectory(project_two)
    add_subdirectory(project_three)

~/lib/communications/CMakeLists.txt

    add_library(Comm_Lib STATIC communications.c)

~/lib/ crypto /CMakeLists.txt

    add_library(Crypto _Lib STATIC crypto.c)

~/lib/error/CMakeLists.txt

    add_library(Error_Lib STATIC error.c)

~/src/project_one/CMakeLists.txt

    add_executable(Project_1A Project_1a.c)
    add_executable(Project_1B Project_1B.c)

    #target_link_library(Project_1A Full_Library) Would like to be able to join all libraries together

~/src/project_two/CMakeLists.txt

    add_executable(Project_Three Project_two.c)

~/src/project_one/CMakeLists.txt

    add_executable(Project_Three Project_three.c)

~/test/CMakeLists.txt

    add_subdirectory(lib_test)
    add_subdirectory(src_test)  

    **Haven’t gotten any deeper in the test CMakeLists.txt

I know I haven't used link_libraries yet, I'm just trying to figure out the best way to go about this.

Thanks for any help!

Roxane answered 24/7, 2019 at 20:9 Comment(0)
P
1

You almost got it: you can link your executables with the libraries defined in other directories. There is no problem with that.

add_executable(Project_1A Project_1a.c)
add_executable(Project_1B Project_1B.c)

target_link_library(Project_1A PUBLIC Full_Library)

However, I would suggest you link only to the parts of the library you are using directly:

add_executable(Project_1A Project_1a.c)
add_executable(Project_1B Project_1B.c)

# Project_1A only use crypto directly in it's code
target_link_library(Project_1A PUBLIC Crypto_Lib) 

# Project_1B use comm and error directly in it's code
target_link_library(Project_1B PUBLIC Comm_Lib Error_Lib) 

Then instead of using the include_directories function, use the target_include_directories. There's an option to add the include directory as a usage requirement. That requirement will be propagated to other libraries which use this one:

target_include_directories(Comm_Lib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

With that line above, anyone who links to Comm_Lib will have the communication library directory as include path.

If you really and to aggregate the three library together, Full_Library can be defined like this:

add_library(Full_Library INTERFACE)

target_link_libraries(Full_Library INTERFACE Comm_Lib Crypto_Lib Error_Lib)
target_include_directories(Full_Library INTERFACE common/include/dir)
Predominance answered 24/7, 2019 at 20:27 Comment(6)
In the cmakelist.txt for Project_1 , I tried adding the Comm Library for Project_1A, but I when I added communications.h into the project_1a.c, it was saying I couldn't find the file. Am I missing something? Also, what is the reason for including the PUBLIC? Thanks!Roxane
Also, say I have one more library (utility) that is used in the other libraries. How do I go about including them in the other libraries?Roxane
@AlexErling if you have include directories required tu use a particular library, you have to add it as an interface include directory. Let me editPredominance
Okay, thanks for info. Last question being, which Cmakes do I do the target include in? In my example, is it ~/src/Cmakelist.txt, or whichever cmake will be used by the library? And I assume I need to do that for each library I add?Roxane
@AlexErling you can add a pure interface library that has the include dir: add_library(common INTERFACE) and add the include directory target_include_directory(common INTERFACE your/include/dir)Predominance
@AlexErling I added an example of this in the last examplePredominance

© 2022 - 2024 — McMap. All rights reserved.