C++ / CMake / Conan.io - 'Undefined Reference to Class::Method' when including header - c++

I'm having a little trouble when compiling a project, using Conan.io and CMake.
I'm building a small OpenGL-based project. I use an MVC architecture. I want CMake to produce two distinct .exe :
main.exe being a small GLFW window with a simple OpenGL context. It builds and works totally well, using conan.io to manage the libs used.
pentest.exe being a simple test executable which I want to use to test some basics functions from my model. This one won't be compiled when I call the make command.
Here my simplified project architecture :
├───build
│ ├───.cmake
│ │
│ ├───bin
│ │ └─── // .exe files are here
│ │
│ ├───CMakeFiles
│ │ └─── // Cmake files are here
│ │
│ └─── // ...
│
├───include
│ ├───GL
│ │ └─── GLU.h
│ │
│ └───model
│ ├───Block.hpp
│ └───GameGrid.hpp
│
├───src
│ ├───model
│ │ ├───Block.hpp
│ │ └───GameGrid.hpp
│ │
│ ├───main.cpp
│ └───pentest.cpp
│
├───CMakeLists.txt
└───conanfile.txt
Please note that :
pentest.cpp doesn't rely on any external libs.
Even though my GameGrid class is a template class, I made the header include the implementation file at the end (following this StackOverflow question).
I'm very, very bad with CMake.
CMake command is doing very well, the errors are occuring when the make command is calling the linker for pentest.exe.
Here is my CMakeLists.txt :
cmake_minimum_required(VERSION 2.8.12)
project(TheEndless)
add_definitions("-std=c++17")
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
include_directories(
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/model
)
link_directories(${CMAKE_SOURCE_DIR}/lib)
add_executable(main src/main.cpp)
add_executable(pentest src/pentest.cpp)
target_link_libraries(main ${CONAN_LIBS})
target_link_libraries(pentest ${CONAN_LIBS})
Here is my pentest.cpp :
#include <iostream>
#include <string>
#include "model/Block.hpp"
#include "model/GameGrid.hpp"
int main(int argc, char const *argv[]) {
theendless::model::Block b;
theendless::model::GameGrid<1, 1> g;
g(0, 0) = b;
std::string s(g(0, 0).get_name());
std::cout << s << std::endl;
return 0;
}
Here is my model/Block.hpp :
#ifndef THEENDLESS_MODEL_BLOCK_HPP
#define THEENDLESS_MODEL_BLOCK_HPP
#include <string>
namespace theendless::model {
class Block {
private:
std::string name;
public:
Block();
Block(std::string name);
std::string get_name() const;
void set_name(const std::string newName);
};
}
#endif
Here is my model/Block.cpp:
#include "model/Block.hpp"
#include <string>
namespace theendless::model {
Block::Block() : name("default_name") {}
Block::Block(std::string name) : name(name) {}
std::string Block::get_name() const { return this->name; }
void Block::set_name(const std::string newName) { this->name = newName; }
}
Here is the errors that are shown by make :
PS C:\projects\TheEndless\build> make
Scanning dependencies of target pentest
[ 75%] Building CXX object CMakeFiles/pentest.dir/src/pentest.cpp.obj
[100%] Linking CXX executable bin/pentest.exe
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/pentest.dir/objects.a(pentest.cpp.obj): in function `main':
C:/projects/TheEndless/src/pentest.cpp:9: undefined reference to `theendless::model::Block::Block()'
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/projects/TheEndless/src/pentest.cpp:13: undefined reference to `theendless::model::Block::get_name[abi:cxx1c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/pentest.dir/objects.a(pentest.cpp.obj): in function `std::array<theendless::model::Block, 1ull>::array()':
c:/mingw/include/c++/9.2.0/array:94: undefined reference to `theendless::model::Block::Block()'
collect2.exe: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/pentest.dir/build.make:107: bin/pentest.exe] Error 1
make[1]: *** [CMakeFiles/Makefile2:124: CMakeFiles/pentest.dir/all] Error 2
make: *** [Makefile:103: all] Error 2
Note that including model/Block.cpp to pentest.cpp makes the problem disappear, but I kinda want to make the project be clean, so I would like not to do this.
Additional infos :
I'm on windows 10.
I'm using VSCode to edit my files, and I compile by typing make in the integrated *PowerShell terminal.
I'm using a Mingw distro to compile.
Any help would be greatly appreciated ! :)

I'm not a CMake or compiler expert, but here's how I understand what's going on.
The compiler does not search around for any headers or source files unless it is told that it has to. But when does the compiler have to search for them?
The file (usually headers) are included in a file that the compiler already knows about.
The file has explicitly been made known to the compiler (e.g. inside a CMakeLists.txt).
In your case, the compiler knows about the header file, because it was #included inside the pentest.cpp source file (variant 1. from above). And how did the compiler know about pentest.cpp? It was explicitly stated inside the function add_executable that the specific build target pentest is built from this file.
Now what about Block.cpp? It was not known to the compiler because it neither was included nor stated inside the CMakeLists.txt, that the compiler has to use this file. So the compiler cannot know about it.
As you already mentioned, including the .cpp file is not a good style. One huge advantage (in my opinion) of only including header files is that if the implementation of a function changes (not its declaration, but the body of the function) you don't have to recompile everything where it's used. You just have to recompile that one .cpp file.
So what's the solution? You have to make the compiler be aware of all the source files that should be used to build your target pentest. Therefore, you have to add those source files to the function add_executable. The CMake docs for add_executable tell you the following.
add_executable(<name> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
Adds an executable target called to be built from the source files listed in the command invocation.
So you have to add all the source files which shall be used for building your target to the same add_executable command invocation. In your case, the CMakeLists.txt would look like this. Note that I had to add target_compile_features and remove add_compile_definitions on my machine in order to enforce the usage of C++17.
cmake_minimum_required(VERSION 2.8.12)
project(TheEndless)
# add_definitions("-std=c++17") # does not work on my Windows 10 machine
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
include_directories(
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/model
)
link_directories(${CMAKE_SOURCE_DIR}/lib)
add_executable(main src/main.cpp)
# add all source files needed to build to the executable
# GameGrid.cpp is not needed because it is included in the header.
add_executable(pentest src/pentest.cpp src/model/Block.cpp)
target_link_libraries(main ${CONAN_LIBS})
target_link_libraries(pentest ${CONAN_LIBS})
target_compile_features(pentest PRIVATE cxx_std_17) # added to really use C++17, see the docs for explanation
Only "problem" I saw: Visual Studio marked Block.hpp, GameGrid.hpp, and GameGrid.cpp as "external dependencies". If you want them to be shown as part of your target, you also may add them to add_executable. I'm not sure if there is another solution as it seems to be a little bit redundant.

Related

g++ can't locate header files while CMake compilation is successful

I've a project structure like this:
project root
│ CMakeLists.txt
│
└───common-libs
│ │ CMakeLists.txt
│ │ libFiles.cpp
│ │ libFiles.h
│ │ ...
│
└───src
│ │ CMakeLists.txt
│ │ main.h
│ │ main.cpp
common-libs folder contains my own implementations of some functions. I can include them in main.h with #include <libFiles.h> without any problem. Cmake compiles it. Problem occured whenver I try to debug the main.cpp on Visual Studio Code. Normally I have a task.json file something like this:
{
"command": "/usr/bin/g++",
"args": [
"-std=c++17",
"-g",
"-I",
"${workspaceFolder}/common-lib/*.cpp",
"${workspaceFolder}/common-lib/*.h",
"-o",
"main",
"-lpthread"
...
]
}
There was a older version of the project where where I included the libraries with their relative path like so: #include "../common-libs/libFiles.h" and with task.json above I could debug without a problem. At that time there was no CMake in the project. While adding CMake I wanted to decouple the common-lib.
Problem
As I said, this code compiles with CMake. Although I give include directories on arguments to g++, whenever I try to run this on debug on VS Code, compiler seems to not see the files. Saying no such file or directory.
My assumption is since I'm not using any path -relative or not- and calling #include <someFile.h> like this, does compiler looks at just default directories and tries to find that file in those directories (in this case just default headers)? I either need to change the way I include header files, or I need to show the compiler where it can find the files.
What can I do to solve this?
If needed:
CMakeLists.txt on common-lib is something like this:
add_library(common-lib STATIC libFiles.cpp ...) # in reality there are more files of course
target_link_libraries(common-lib pthread curl ... )
target_include_directories(common-lib PUBLIC ${CMAKE_CURRENT_LIST_DIR})
and CMakeLists.txt on src:
add_executable(main main.h main.cpp)
target_link_libraries(main PRIVATE common-lib)

CMake: Some include directories defined in source files, but undefined in headers for nested target

Given the following project structure:
.
└── library/
├── CMakeLists.txt
├── include/
│ └── class1.hpp
├── src/
│ └── class1.cpp
├── build/
│ ├── _deps/
│ │ └── fmt-build
│ └── sample/
│ └── app_using_library.exe
└── sample/
├── CMakeLists.txt
└── main.cpp
CMakeLists.txt of library:
project(library)
include(FetchContent)
FetchContent_Declare(
fmt
URL https://github.com/fmtlib/fmt/releases/download/9.1.0/fmt-9.1.0.zip
)
FetchContent_MakeAvailable(fmt)
add_library(library STATIC
"src/class1.cpp"
"include/class1.hpp"
target_include_directories(library PUBLIC include)
target_link_libraries(library PRIVATE fmt::fmt)
CMakeLists.txt of app_using_library:
project(app_using_library)
add_executable(app_using_library main.cpp)
target_link_libraries(app_using_library PRIVATE library)
class1.hpp:
#include "fmt/core.h" // cannot open source file "fmt/core.h"
class1.cpp:
#include "fmt/core.h" // works fine
Is there a possible cause or explanation for why the fmt headers are includable in class1.cpp, but not in class1.hpp when building both library and app_using_library? The include works correctly in the header when just building library
The compiler couldn't find the fmt headers in "class1.hpp", but it could find them in "class1.cpp".
The full error:
FAILED: sample/CMakeFiles/app_using_library.dir/main.cpp.obj
C:\msys64\mingw64\bin\g++.exe -ID:/Programming/cpp/library/include -g -std=gnu++20 -MD -MT sample/CMakeFiles/app_using_library.dir/main.cpp.obj -MF sample\CMakeFiles\app_using_library.dir\main.cpp.obj.d -o sample/CMakeFiles/app_using_library.dir/main.cpp.obj -c D:/Programming/cpp/library/sample/main.cpp
In file included from D:/Programming/cpp/library/sample/main.cpp:2:
D:/Programming/cpp/library/include/class1.hpp:4:10: fatal error: fmt/core.h: No such file or directory
4 | #include "fmt/core.h"
| ^~~~~~~~~~~~
compilation terminated.
It fails while compiling "app_using_library" because only "library" knows about fmt.
To resolve that you need to also include the information you have defined about fmt into the app_using_library CMakeLists.txt
Based on the answer from Tsyarev in the comments:
Such includes should only be done in private headers, i.e. headers not included in the INCLUDE_DIRECTORIES for that target. This prevents any executable target using library from also having to link to the library included in public headers.
Tsyarev's answers:
There is a notion about library's public header: that header is intended to be available to the consumers of the library. E.g., class1.hpp is public header for your library. For make a header available to the consumers, the header should be located in the PUBLIC include directory of your library. Any header included by a public header is public by yourself. E.g., since class1.hpp is a public header of the library and includes fmt/core.h, then fmt/core.h is a public header for your library too. And you need to make this headers accessible via PUBLIC include directory.
If you use fmt/core.h only in the private headers of your library, then your current code should work: library is PRIVATE linked with fmt::fmt, app_using_library is linked with library.

ImGui can't find any definitions

OS: Windows10
Editor: VScode
Build: CMake
Compiler: GCC(actually MinGW)
ImGui branch: master (I didn't use the release tag branch), GLFW+OpenGL3 implementations
Here is the situation, I'm rewriting my learnOpenGL project with some more features added to it, like using yaml to do the initialization config. Now I want to add a visual config window when I run my opengl demo, so I could adjust colors or shader options or whatever.
I choose ImGui and followed many tutorials from other sites, when I add ImGui cpp files and compile them into a static library, the imgui_gui.cpp(not only this one) can't find any definitions of functions it contains(nearly all).
Below is the structure of my demo's workspace(simplified):
I:.
├───.vscode
├───CMakeLists.txt
├───app
│ ├───CMakeLists.txt
│ └───ImGui_test.cpp
├───bin
├───build
├───config
├───images
├───include
│ ├───glad
│ ├───GLFW
│ ├───glm
│ ├───ImGui
│ │ ├───imconfig.h
│ │ ├───imgui.h
│ │ ├───imgui_impl_glfw.h
│ │ ├───imgui_impl_opengl3.h
│ │ ├───imgui_impl_opengl3_loader.h
│ │ ├───imgui_internal.h
│ │ ├───imstb_rectpack.h
│ │ ├───imstb_textedit.h
│ │ └───imstb_truetype.h
│ ├───KHR
│ ├───myImplement
│ ├───stb_image
│ └───yaml-cpp
├───lib
│ ├───libglfw3.a
│ ├───libimgui.a
│ ├───libmysrc.a
│ └───libyaml-cpp.dll
├───model
├───shader
│ ├───shader_fragment
│ └───shader_vertex
└───src
├───CMakeLists.txt
├───config.cpp
├───glad.c
├───shader.cpp
├───stb_image.cpp
└───ImGui
├───imgui.cpp
├───imgui_demo.cpp
├───imgui_draw.cpp
├───imgui_impl_glfw.cpp
├───imgui_impl_opengl3.cpp
└───imgui_widgets.cpp
The problem is, when I compile other opengl demos, this build system works fine, all static and dynamic libraries can be found and linked properly(glfw, yaml, opengl32, and the lib made of cpp files from the 'src' dir except for the cpp files in the 'ImGui' dir), but adding libimgui.a seems not providing correct definitions for demos that contains any imgui function.
// a piece of error in cmd
// undefined reference of imgui.cpp(part of)
I:/VScode_projects/shader_toy/src/ImGui/imgui.cpp:2557: undefined reference to `ImGui::TableEndRow(ImGuiTable*)'
../../lib/libimgui.a(imgui.cpp.obj): In function `ImGuiListClipper::Begin(int, float)':
I:/VScode_projects/shader_toy/src/ImGui/imgui.cpp:2595: undefined reference to `ImGui::TableEndRow(ImGuiTable*)'
../../lib/libimgui.a(imgui.cpp.obj): In function `ImGuiListClipper::Step()':
I:/VScode_projects/shader_toy/src/ImGui/imgui.cpp:2652: undefined reference to `ImGui::TableEndRow(ImGuiTable*)'
../../lib/libimgui.a(imgui.cpp.obj): In function `ImGui::GcCompactTransientMiscBuffers()':
I:/VScode_projects/shader_toy/src/ImGui/imgui.cpp:3357: undefined reference to `ImGui::TableGcCompactSettings()'
../../lib/libimgui.a(imgui.cpp.obj): In function `ImGui::NewFrame()':
I:/VScode_projects/shader_toy/src/ImGui/imgui.cpp:4516: undefined reference to `ImGui::TableGcCompactTransientBuffers(ImGuiTable*)'
I:/VScode_projects/shader_toy/src/ImGui/imgui.cpp:4519: undefined reference to `ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData*)'
../../lib/libimgui.a(imgui.cpp.obj): In function `ImGui::Initialize()':
// undefined reference in imgui_demo.cpp(part of)
../../lib/libimgui.a(imgui_demo.cpp.obj): In function `ShowPlaceholderObject':
I:/VScode_projects/shader_toy/src/ImGui/imgui_demo.cpp:7096: undefined reference to `ImGui::TableNextRow(int, float)'
I:/VScode_projects/shader_toy/src/ImGui/imgui_demo.cpp:7097: undefined reference to `ImGui::TableSetColumnIndex(int)'
I:/VScode_projects/shader_toy/src/ImGui/imgui_demo.cpp:7100: undefined reference to `ImGui::TableSetColumnIndex(int)'
I:/VScode_projects/shader_toy/src/ImGui/imgui_demo.cpp:7116: undefined reference to `ImGui::TableNextRow(int, float)'
I:/VScode_projects/shader_toy/src/ImGui/imgui_demo.cpp:7117: undefined reference to `ImGui::TableSetColumnIndex(int)'
I:/VScode_projects/shader_toy/src/ImGui/imgui_demo.cpp:7122: undefined reference to `ImGui::TableSetColumnIndex(int)'
I:/VScode_projects/shader_toy/src/ImGui/imgui_demo.cpp:7128: undefined reference to `ImGui::NextColumn()'
Also, three CMakeLists.txt in root directory, src and app:
// CMakeLists.txt in root directory
CMAKE_MINIMUM_REQUIRED(VERSION 3.19)
PROJECT(shader_toy)
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_STANDARD 14)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include)
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/lib)
SET(GL_LIB opengl32)
OPTION(DEBUG "debug switch" OFF)
OPTION(GEN_SHARED_LIB "generate shared lib .so" OFF)
OPTION(GEN_STATIC_LIB "generate static lib .a" ON)
ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/src)
ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/app)
//CMakeLists.txt in src directory
AUX_SOURCE_DIRECTORY(. SRC_LIST)
AUX_SOURCE_DIRECTORY(ImGui IMGUI_LIST)
IF(DEBUG)
ADD_DEFINITIONS(-DDEBUG)
ENDIF()
IF(SRC_LIST)
ADD_LIBRARY(mysrc STATIC ${SRC_LIST})
ENDIF()
IF(IMGUI_LIST)
ADD_LIBRARY(imgui STATIC ${IMGUI_LIST})
ENDIF()
MESSAGE("following source files will be linked into library:")
MESSAGE("------------------- SRC LIST -------------------")
FOREACH(src ${SRC_LIST})
MESSAGE("${src}")
ENDFOREACH()
MESSAGE("------------------- LIST END -------------------")
// CMakeLists.txt in app directory
AUX_SOURCE_DIRECTORY(. APP_LIST)
IF (DEBUG)
ADD_DEFINITIONS(-DDEBUG)
MESSAGE("DEBUG set to ON")
ENDIF()
FILE(GLOB LIB_LIST ${PROJECT_SOURCE_DIR}/lib/*.dll ${PROJECT_SOURCE_DIR}/lib/*.a)
IF (LIB_LIST)
FOREACH (lib ${LIB_LIST})
MESSAGE("lib found: ${lib}")
ENDFOREACH ()
ENDIF()
FOREACH (app ${APP_LIST})
GET_FILENAME_COMPONENT(output ${app} NAME_WE)
ADD_EXECUTABLE(${output} ${app})
IF (LIB_LIST)
FOREACH (lib ${LIB_LIST})
GET_FILENAME_COMPONENT(lib_name ${lib} NAME_WE)
GET_FILENAME_COMPONENT(lib_post ${lib} LAST_EXT)
IF (NOT lib_post)
MESSAGE(FATAL_ERROR "lib format not recognized\n")
ENDIF()
IF (NOT(lib_post STREQUAL ".a" OR lib_post STREQUAL ".so" OR lib_post STREQUAL ".lib" OR lib_post STREQUAL ".dll"))
MESSAGE(FATAL_ERROR "lib format not recognized: ${lib_post}\n")
ENDIF()
STRING(SUBSTRING ${lib_name} 3 -1 lib_name_without_prefix)
MESSAGE("${output} will be linked with: ${lib_name_without_prefix}")
TARGET_LINK_LIBRARIES(${output} ${lib_name_without_prefix})
ENDFOREACH()
MESSAGE("${output} will be linked with: ${GL_LIB}")
TARGET_LINK_LIBRARIES(${output} ${GL_LIB})
ENDIF()
ENDFOREACH()
I know 'undefined reference' is a common linking error in cpp projects, I have fixed many similar problems in my previous cpp projects, but I can't figure out what goes wrong in this one, actually, I have used global search(Ctrl+Shift+f) on these undefined reference functions in VScode, they do don't have formal definitions in any file! All references in search results is the usage or declaration, but no definitions! I don't understand, may be definitions will be generated in compiling???
Will it be the problem in:
wrong platform
missed steps in compiling / incorrect compile methods
wrong OpenGL version(as I don't know which version the opengl32.lib from Windows10 implements)
wrong repo, I should download the release tag instead of master branch
missing definition files, I forget to copy them into my workspace
If you have used the ImGui library, any advice would be appreciate! Thank you!

Generate grpc files for a library target in CMAKE

In the following project structure(from my previous question):
root/
├─ CMakeLists.txt
├─ protocol/
│ ├─ msg.proto
│ ├─ myrpc.proto
│ ├─ CMakeLists.txt
├─ app/
│ ├─ main.cpp
│ ├─ CMakeLists.txt
I could generate the protobuf files and add them as dependency into the app target. Now I am trying to generate grpc files inside the same library.
Something is not right with the grpc generation function, which is based on this answer and blog post;as the following error message is printed:
-- Configuring done
-- Generating done
-- Build files have been written to: /media/davids91/Work/rafko/src/main/cxx/build
[ 1%] Running grpc protocol buffer compiler on /usr/local/bin/grpc_cpp_plugin
/usr/local/bin/grpc_cpp_plugin: File does not reside within any path specified using --proto_path (or -I). You must specify a --proto_path which encompasses this file. Note that the proto_path must be an exact prefix of the .proto file names -- protoc is too dumb to figure out when two paths (e.g. absolute and relative) are equivalent (it's harder than you think).
make[2]: * [protocol/CMakeFiles/protocol.dir/build.make:138: /media/usr/local/bin/grpc_cpp_plugin.grpc.pb.h] Error 1
make[1]: * [CMakeFiles/Makefile2:276: protocol/CMakeFiles/protocol.dir/all] Error 2
make: * [Makefile:103: all] Error 2
I can see that the install folder looks correct, as that is where the grpc library was installed from source.
root CMakeLists.txt:
cmake_minimum_required(VERSION 3.18.4)
project(
root
VERSION 0.1
LANGUAGES CXX
)
add_subdirectory(protocol)
add_subdirectory(app)
protocol CMakeLists.txt:
add_library(protocol)
target_include_directories(protocol
PUBLIC
.
${CMAKE_CURRENT_BINARY_DIR}
${Protobuf_INCLUDE_DIRS}
)
find_package(Protobuf REQUIRED)
find_package(gRPC CONFIG REQUIRED)
target_link_libraries(protocol ${Protobuf_LIBRARIES})
get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION)
protobuf_generate( TARGET protocol LANGUAGE CPP PROTOS msg.proto )
protobuf_generate(
TARGET
protocol
LANGUAGE
grpc
PROTOS
myrpc.proto
PLUGIN
"protoc-gen-grpc=${grpc_cpp_plugin_location}"
)
app CMakeLists.txt:
add_library(app)
target_link_libraries(app PUBLIC protocol)
target_include_directories(app PUBLIC .)
target_sources(app
PRIVATE
main.cpp
)
What might be missing from this solution to generate out the grpc files based on the plugins?
After some experimenting and closely looking at the example here I figured it out!
I updated protocol CMakeLists.txt:
changed
find_package(Protobuf REQUIRED)
to
find_package(Protobuf CONFIG REQUIRED)
I figure it tells CMake that the proto files are being procesed at configuration time, but any deeper explanation is welcome!

CMake No such file or directory

I have a problem building my Qt5 project via cmake.
I run the command cmake .. && make from the directory build and I receive the following error:
/usr/bin/ld: cannot find -lengine-lib
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/blacklist-engine-cli.dir/build.make:102: src/blacklist-engine-cli] Error 1
make[1]: *** [CMakeFiles/Makefile2:117: src/CMakeFiles/blacklist-engine-cli.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
I have searched this topic briefly, however when I ran this project without Qt5Sql, using only Qt5Core I have no problem at all building the project. In order to build the project without Qt5Sql I just have to remove the db folder, and delete lines referring to that in my other CMakeLists.txt files. My question is:
Why does it work if I want to include only Qt5Core, and why does it not work when I also include Qt5Sql? What am I doing wrong including Qt5Sql?
Please do not include answers related to QtCreator, or Qt installation errors. I have checked my Qt installation folder, and I have Qt5Core and Qt5Sql on the same directory level installed.
I am using Ubuntu 20.04, cmake version 3.16.3, Qt version 5.12.8
ls /usr/lib/x86_64-linux-gnu/cmake
Qt5 Qt5Core Qt5Gui Qt5OpenGL Qt5PrintSupport Qt5Test Qt5Xml
Qt5Concurrent Qt5DBus Qt5Network Qt5OpenGLExtensions Qt5Sql Qt5Widgets
I have the following structure in my project:
root
├── CMakeModules
│ └── Qt.cmake
├── build
├── src
│ ├── db
│ │ ├── dbmanager.cpp
│ │ ├── dbmanager.h
│ │ └── CMakeLists.txt
│ ├── engine
│ │ ├── scanner.cpp
│ │ ├── scanner.h
│ │ └── CMakeLists.txt
│ ├── CMakeLists.txt
│ └── main.cpp
└── CMakeLists.txt
CMakeLists.txt:
cmake_minimum_required(VERSION 3.0)
project(blacklist-engine)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules)
add_subdirectory(src)
CMakeModules/Qt.cmake:
set(CMAKE_AUTOMOC ON)
find_package(Qt5 REQUIRED COMPONENTS Core Sql)
src/CMakeLists.txt:
include(Qt)
add_subdirectory(
db
engine
)
add_executable(blacklist-engine-cli main.cpp)
target_link_libraries(
blacklist-engine-cli
Qt5::Core
Qt5::Sql
engine-lib
db-lib
)
src/main.cpp:
#include <QtCore>
#include "db/dbmanager.h"
#include "engine/scanner.h"
...
src/db/CMakeLists.txt (updated):
set (db-lib-source
dbmanager.h
dbmanager.cpp
)
add_library(db-lib ${db-lib-source})
target_link_libraries(
db-lib
Qt5::Sql
)
src/db/dbmanager.h:
#include <QtSql/QSqlDatabase>
...
src/db/dbmanager.cpp:
#include "dbmanager.h"
#include <QtSql/QSqlQuery>
...
src/engine/CMakeLists.txt:
set(engine-lib-source
scanner.h
scanner.cpp
)
add_library(engine-lib ${engine-lib-source})
src/engine/scanner.h:
#include <QtCore>
...
src/engine/scanner.cpp:
#include "scanner.h"
...
The reason for the error is because engine-lib is never built, and its CMake file is never even processed. The offending line in your CMake file is this one:
add_subdirectory(
db
engine
)
When using add_subdirectory in this manner, the second argument becomes the binary directory for the generated content related to db. As a result, you may notice that CMake placed some build artifacts in your src/engine directory, which is probably not what you want.
To fix this, you must call add_subdirectory consecutive times for including multiple sub-directories.
add_subdirectory(db)
add_subdirectory(engine)