1

I'm creating a project that makes use of CMake.

I have an include folder for headers and an src folder for source code. When attempting to build the project with cmake --build ., I get an "undefined reference" error:

/sdcard/dev/cpp/Bedrock++/src/main.cpp:(.text+0x70): undefined 
reference to `ChatFormat::Blue'

Additional detail below:

$ cmake --build .
-- Configuring done
-- Generating done
-- Build files have been written to: /sdcard/dev/cpp/Bedrock++
Scanning dependencies of target Bedrock++
[ 33%] Building CXX object src/CMakeFiles/Bedrock++.dir/Server.cpp.o
[ 66%] Building CXX object src/CMakeFiles/Bedrock++.dir/main.cpp.o
[100%] Linking CXX executable Bedrock++
CMakeFiles/Bedrock++.dir/main.cpp.o: In function `main':
/sdcard/dev/cpp/Bedrock++/src/main.cpp:(.text+0x70): undefined 
reference to `ChatFormat::Blue'
clang-5.0: error: linker command failed with exit code 1 (use -v to see 
invocation)
make[2]: *** [src/CMakeFiles/Bedrock++.dir/build.make:121: 
src/Bedrock++] Error 1
make[1]: *** [CMakeFiles/Makefile2:86: 
src/CMakeFiles/Bedrock++.dir/all] Error 2
make: *** [Makefile:130: all] Error 2

Project root CMakeLists.txt

cmake_minimum_required(VERSION 2.8.7)

# Build all dependent libraries as static

project(Bedrock++)

#add_subdirectory(lib/json)

add_subdirectory(src)
add_subdirectory(include)

src/CMakeLists.txt

project(bedrock++)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

include_directories("${PROJECT_SOURCE_DIR}/include")

file(GLOB SOURCES "*.cpp")

add_executable(${PROJECT_NAME} ${SOURCES})

include/CMakeLists.txt

install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" FILES_MATCHING PATTERN "*.h")

main.cpp

#include <iostream>
#include <string>
#include "util/ChatFormat.h"

int main()
{
    std::cout << "Hello World! " << ChatFormat::Blue << "hey" << std::endl;
}

The ChatFormat.h header is found in include/util/ChatFormat.h and contains the following for every different colour:

static const std::string Black;

I've attempted to solve the problem myself to no avail with hours of research on the internet proving to be a dead end. I hope I didn't miss something obvious.

Any help would be greatly appreciated.

Luke
  • 39
  • 1
  • 8
  • 1
    Please post the full text of the linker error ("Undefined reference") which you're getting (i.e. which reference is undefined?), and also the full declaration of `Blue` (including any containing namespace/class) in `ChatFormat,h`. It's hard to answer a question without having all the data, and you should make sure your questions always contain a [mcve]. – Angew is no longer proud of SO Oct 23 '17 at 12:42
  • @Angew Blue is the same as Black, except it has a different number in quotes (which shouldnt make any difference). I'll uldate it with the error – Luke Oct 23 '17 at 13:05
  • You've shown the definition of `Black` in the `.cpp` file, but I was asking you to also show its declaration in the `.h`. – Angew is no longer proud of SO Oct 23 '17 at 13:08
  • @Angew I updated the question – Luke Oct 23 '17 at 13:10
  • 1
    That update cannot be right, since you're accessing it as `ChatFormat::Blue` and the compiler is not complaining, but you've not shown any `ChatFormat` context around the declaration. Please provide **accurate** info if you want help. See my earlier comment: "including any containing namespace/class" – Angew is no longer proud of SO Oct 23 '17 at 13:12
  • Absolutely a duplicate – Luke Oct 23 '17 at 22:14

2 Answers2

1

Header inclusion error

The problem with "Header file not found" is that your src/CMakeLists.txt contains a project() command. That declares a new CMake project (think Visual Studio solution) for that subtree. PROJECT_SOURCE_DIR will therefore refer to that project's source directory within that subtree. In other words, your ${PROJECT_SOURCE_DIR}/include resolves to ${CMAKE_SOURCE_DIR}/src/include.

Based on your CMake file structure, I'd say it makes no sense for src/CMakeLists.txt to contain a project() command. Just remove it, and include paths should start working for you.

Unresolved reference error

The question doesn't contain enough information to solve this, but my hunch is you're somehow messing up internal linkage (static) and definition in a dedicated source file. These normally don't mesh at all. You might want to read through the canonical Undefined Reference question here on Stack Overflow.

Community
  • 1
  • 1
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Thanks for the first solution :) For the second one i copied off https://github.com/cuberite/cuberite/blob/e1d3b201bd7a22f2924182f0243bb51433080c79/src/ChatColor.cpp and https://github.com/cuberite/cuberite/blob/e1d3b201bd7a22f2924182f0243bb51433080c79/src/ChatColor.h which seems to work there but not for me. Don't forget i mentioned that it worked before then i started changing directorh structure and stuff and it stopped working. Weird. – Luke Oct 23 '17 at 12:49
  • @TheDiamondYT BTW, since you're using the *heavily discouraged* `file(GLOB)` to get your source file list: are you sure that `ChatFormat.cpp` is part of your source list? Is it on the same directory level as `main.cpp`? – Angew is no longer proud of SO Oct 23 '17 at 13:10
  • Oh wow. No it's not. How would i look for files in all directories then? – Luke Oct 23 '17 at 13:21
  • @TheDiamondYT Follow [CMake's advice](https://cmake.org/cmake/help/latest/command/file.html) in the (`file(GLOB)` section) and list all files manually (you can dedicate a file to setting a variable and `include()` that file if you don't want to pollute your CMakeList). You'll save yourself a lot of trouble – Angew is no longer proud of SO Oct 23 '17 at 13:28
1

The CMake output suggests that 'ChatFormat.cpp', which contains the definition of 'ChatFormat::Black', is not being compiled. Only 'Server.cpp' and 'main.cpp' are being compiled.

I'm guessing that 'ChatFormat.cpp', like it's corresponding header, is under a 'utils' directory? But the GLOB command you are using to find your source files will only be finding files name *.cpp in the root folder. You might want to try changing 'GLOB' to 'GLOB_RECURSE' so it will pick up files in subfolders, though it is generally recommended that you avoid using globbing entirely and list each source file explicitly...

Sean Burton
  • 907
  • 7
  • 15