Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple multiple directories CMake

Tags:

c++

cmake

I just would like to create my CMakeLists.txt like this, but the CMake guide is not that user friendly for beginners, I have already researched too much, do not downvote, please.

I have seen some solutions including in the add_executable() every source file manually, but I would like to make it more generic. Also, I would not like to use the file(GLOB SOURCES *.cpp *.h).

By the way, I am just attempting to create a Unix Makefile with the command

cmake -G 'Unix Makefiles'..

How can I do this?

CMakeLists.txt
build/
    ...
project/
    CMakeLists.txt
    Inc/
        CMakeLists.txt
        *.h
    Src/
        CMakeLists.txt
        main.cpp
        *.cpp

I have so far for the main directory/CMakeLists.txt

cmake_minimum_required(VERSION 3.17)

project(my_project)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a")

add_subdirectory(project)

for the project/CMakeLists.txt

add_subdirectory(Inc)
add_subdirectory(Src)

add_executable(exec ${Sources})

target_link_libraries(exec ${Headers})

For the Inc/CMakeLists.txt

add_library(
    Headers
    H1.h
    H2.h
    ...
    Hn.h
)

and for the Src/CMakeLists.txt

set(Sources main.cpp
        Src1.cpp
        Src2.cpp
        ...
        Srcn.cpp
    )

As it is so far, it throws the following error

-- Version: 7.0.3
-- Build type:
-- CXX_STANDARD: 11
-- Required features: cxx_variadic_templates
-- Configuring done
CMake Error: Cannot determine link language for target "exec".
CMake Error: CMake can not determine linker language for target: exec
CMake Error: Cannot determine link language for target "Headers".
CMake Error: CMake can not determine linker language for target: Headers
-- Generating done
CMake Generate step failed.  Build files cannot be regenerated correctly.

like image 249
Andres Avatar asked Sep 05 '26 17:09

Andres


1 Answers

add_library(
   Headers
   H1.h
   H2.h

does not add a include directory to search path. It only adds the headers to sources - and because headers are not compiled, it effectively does nothing. You can do that with target_include_directories. Because cmake doesn't know if these are C or C++ headers, it cannot determine the link language.

add_subdirectory(Src)
add_executable(exec ${Sources})

add_subdirectory introduces a new "scope". Variables set in add_subdirectory are not visible outside, unless you set them with PARENT_SCOPE like set(var "value" PARENT_SCOPE). ${Sources} is effectively empty, so it does add_executable(exec) with no sources, so cmake cannot determine the link language.

target_link_libraries(exec ${Headers})

A target is not a variable. ${Headers} is empty. To link with a target just use it's name.

I also subjectively advice do not use mixed case variables (and folder names).

You could:

# project/CMakeLists.txt
include(Inc/CMakeLists.txt)
include(Src/CMakeLists.txt)
add_executable(exec ${exec_sources} ${exec_headers})
target_include_directories(exec PUBLIC Inc)

# Inc/CMakeLists.txt
set(exec_headers
    Inc/H1.h
    Inc/H2.h
    ...
    Inc/Hn.h
)

# Src/CMakeLists.txt    
set(exec_sources
        Src/main.cpp
        Src/Src1.cpp
        Src/Src2.cpp
        ...
        Src/Srcn.cpp
)
# Instead of `Src/` in front you could write a `foreach()` loop.

but I do not see a point in having so many CMakeLists.txt. Just have one file:

# project/CMakeLists.txt
include(Inc/CMakeLists.txt)
include(Src/CMakeLists.txt)
add_executable(exec
        Src/main.cpp
        Src/Src1.cpp
        Src/Src2.cpp
        ...
        Src/Srcn.cpp

    Inc/H1.h
    Inc/H2.h
    ...
    Inc/Hn.h
)
target_include_direcotories(exec PUBLIC Inc)

Och, there is also target_sources you could use, so you could also do it like this I think:

# project/CMakeLists.txt
add_executable(exec ${exec_sources} ${exec_headers})
add_subdirectory(Inc)
add_subdirectory(Src)

# Inc/CMakeLists.txt
target_include_directories(exec PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_sources(exec PRIVATE 
    H1.h
    H2.h
    ...
    Hn.h
)

# Src/CMakeLists.txt    
target_sources(exec PRIVATE
        main.cpp
        Src1.cpp
        Src2.cpp
        ...
        Srcn.cpp
)
like image 141
KamilCuk Avatar answered Sep 07 '26 08:09

KamilCuk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!