4

I am trying to nest code under specific namespace for organizational purposes. Below is an MVP, I cannot spot the issue in my code. Not sure how you define this nesting or export it to CMakeLists.txt and Linking. It happens only if a wrap the class inside namespaces.

demo.h:

#pragma once
#include "../../third-party/fmt/include/fmt/core.h"
#include "../../third-party/fmt/include/fmt/color.h"

namespace demo {
    namespace app {
        class ApplicationDemo{
        public:
            void entry();
        };
    }
}

demo.cpp:

#include "demo.h"

namespace demo
{
    namespace app {
        void ApplicationDemo::entry(){
             std::string m_ascii = R"(
    ____                   
    |    \  ___  _____  ___ 
    |  |  || -_||     || . |
    |____/ |___||_|_|_||___|                    
)";
            fmt::print(fmt::emphasis::bold | fg(fmt::color::orange_red), m_ascii);
        }
    }
}

main.cpp:

#include <iostream>
#include "demoapp/demo.h"

int main(int argc, char const *argv[])
{
    demo::app::ApplicationDemo m_demo;

    m_demo.entry();
    std::cin.get();
    return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)

set(CMAKE_CXX_STANDARD 17)
project(demo)

set(CMAKE_CXX_FLAGS
        "${CMAKE_CXX_FLAGS} \
        -Wall \
        -fdiagnostics-color=always \
        -mavx")

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

include_directories(./)

add_subdirectory(third-party/fmt EXCLUDE_FROM_ALL)
target_compile_options(fmt PRIVATE -w)

add_subdirectory(src/demoapp)

set(third_parties fmt)

set(SOURCES src/main.cpp)
add_executable(demo src/main.cpp)
target_link_libraries(demo ${third_parties})

Build output:

[main] Building folder: experiment 
[build] Starting build
[proc] Executing command: chcp
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build c:/GitHub/experiment/build --config Debug --target all -j 10 --
[build] [ 20%] Building CXX object third-party/fmt/CMakeFiles/fmt.dir/src/format.cc.obj
[build] [ 40%] Building CXX object third-party/fmt/CMakeFiles/fmt.dir/src/os.cc.obj
[build] [ 60%] Linking CXX static library ..\..\lib\libfmtd.a
[build] [ 60%] Built target fmt
[build] [ 80%] Building CXX object CMakeFiles/demo.dir/src/main.cpp.obj
[build] [100%] Linking CXX executable bin\demo.exe
[build] C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\demo.dir/objects.a(main.cpp.obj): in function `main':
[build] C:/GitHub/experiment/src/main.cpp:8:(.text+0x1c): undefined reference to `demo::app::ApplicationDemo::entry()'
[build] collect2.exe: error: ld returned 1 exit status
[build] mingw32-make[2]: *** [CMakeFiles\demo.dir\build.make:100: bin/demo.exe] Error 1
[build] mingw32-make[1]: *** [CMakeFiles\Makefile2:98: CMakeFiles/demo.dir/all] Error 2
[build] mingw32-make: *** [Makefile:135: all] Error 2
[proc] The command: "C:\Program Files\CMake\bin\cmake.EXE" --build c:/GitHub/experiment/build --config Debug --target all -j 10 -- exited with code: 2
[driver] Build completed: 00:00:04.365
[build] Build finished with exit code 2

EDIT: I put things like this,

/src/demoapp/
CMakeLists.txt,
demo.cpp
demo.h

/src/main.cpp

The CMakeLists.txt of demoapp:

add_library(demoapp
demo.cpp)

target_link_libraries(demoapp fmt)

if(WIN32)
    target_link_libraries(demoapp)
else()
    target_link_libraries(demoapp stdc++fs)
endif()

Then, I added this line add_subdirectory(src/demoapp) to the parent root CMakeLists.txt. But, when I do this, which is my desired goal. Sorry I didn't specify this earlier, when I receive the same error as above. Whereas, if I do the way you showed me, then it works brilliantly.

I appreciate any valuable information on this. Thanks in advance.

Alix Blaine
  • 585
  • 2
  • 16

1 Answers1

1

You forgot to add demo.cpp to your executable. It is not being compiled and linked as part of the project.

add_executable(demo
    src/main.cpp
    src/demo.cpp
    src/demo.h)

Note: adding demo.h to the executable isn't strictly necessary, but useful for IDEs because it makes the header part of the project. For example, QtCreator relies on this.

void ApplicationDemo::entry() is located in demo.cpp, and if if you don't add demo.cpp to the executable, the definitions inside won't be available to the rest of the program, and you get linker errors.

Furthermore, if you want link to a library, it is necessary to write:

target_link_libraries(demo demoapp)

Merely adding a subdirectory where demoapp is located isn't enough; it doesn't yet tell CMake that the library is linked with the demo executable.

See also CMake link library from subdirectory

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
  • **Jan**, thanks. Please see my edit. – Alix Blaine Aug 31 '23 at 12:47
  • Why can't it be done the way, I have done it there? With: `add_library()` in a CMakeLists.txt under the src/demoapp ? – Alix Blaine Aug 31 '23 at 12:53
  • @AlixBlaine did you link the `demo` executable with the `demoapp` library using `target_link_libraries` ? I don't see that in your code – Jan Schultke Aug 31 '23 at 13:34
  • What do you mean Jan? – Alix Blaine Aug 31 '23 at 14:19
  • @AlixBlaine I see you have linked `target_link_libraries(demo ${third_parties})`, but shouldn't you also have linked `target_link_libraries(demo demoapp)` ? – Jan Schultke Aug 31 '23 at 14:26
  • Demo app is my own code not third-party, shouldn't it be enough to `add_subdirectory(src/demoapp)` ? – Alix Blaine Aug 31 '23 at 14:29
  • 1
    @AlixBlaine `add_subdirectory` just adds a directory to the build. It doesn't mean that all executables will be linked to all libraries that you have created in the directory. It just lets CMake know that a subdirectory is somehow involved in the build process. – Jan Schultke Aug 31 '23 at 14:35
  • Yes, but, it produces a *.dll for my own code the demoapp, can I tell it to statically link and embed that one? – Alix Blaine Aug 31 '23 at 14:53
  • 1
    @AlixBlaine see [CMake: include library dependencies in a static library](https://stackoverflow.com/q/14199708/5740428) – Jan Schultke Aug 31 '23 at 17:08