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

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)

Related

How to set CMake to have root directory in include paths

I'm a little new here, this is my first post. I have a c++ project in CLion that is structured like so:
project-root/
├─ cmake-build-debug/
├─ controller/
├─ model/
│ ├─ foo/
│ │ ├─ a.h *
│ │ ├─ a.cpp *
│ ├─ bar/
│ │ ├─ b.h *
│ │ ├─ b.cpp *
├─ view/
│ ├─ c.h *
│ ├─ c.cpp *
├─ new_file
├─CMakeLists.txt
├─main.cpp *
I've starred the actual cpp and h files just for visual purposes.
In a.h, suppose I'd like to include b.h. The way I'd like to do this in a.h is by doing:
#include "project-root/model/bar/b.h"
Similarly, I'd like to use this pattern for all includes. For example, if I wanted to include a.h in c.h, in c.h I'd do:
#include "project-root/model/foo/a.h"
And, just one more example, even if I was in main.cpp and I'd like to include c.h, I'd do:
#include "project-root/view/c.h"
I tried doing the following in my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.22)
project(project-root)
set(CMAKE_CXX_STANDARD 17) // this ".." seems incorrect
include_directories(..)
add_executable(project-root main.cpp <the rest of all the .h and .cpp files>)
And actually, this works! However, I think it seems a little weird to have include_directories(..), since there's a relative path above the project root. That doesn't seem correct to me.
I originally thought include_directory(.) would work, but unfortunately, no dice. When I try to do #include project-root/model/bar/b.h in a.h, I get an error saying project-root/model/bar/b.h not found
I would also advise against .. since you are depending on name of a folder that you might not necessarily control. Well, it depends on how you plan to distribute the code, for example if you use git, then project-root folder itself should be inside the repository, not the other way around.
The include paths have little to do with CMake, it will just pass them (their absolute versions) to the compiler.
In C++, you have two "types" of includes - #include "foo.h" or #include <foo.h>. Both are implementation-specific, i.e. the compiler dictates how they are interpreted. In practice, <> searches on include paths, "" searches relative paths first, then behaves like <>. One convention is to use <> for public headers in the include path and "" for relative includes or private headers.
Libraries might want to distinguish between public and private headers. Public ones are meant for the user of the library, private ones are internal. But this is not universally adhered to, sometimes the are internal directories...
Personally, I like to use the following structure for my projects:
. // root of a git repository
├── include/
│ └── project-name/
│ ├── model/
│ │ └── foo/
│ │ └── a.h
│ └── view/
│ └── c.h
├── src/
│ ├── model/
│ │ ├── foo/
│ │ │ └── a.cpp
│ │ └── bar/
│ │ ├── b.h
│ │ └── b.cpp
│ ├── view/
│ │ └── c.cpp
│ └── main.cpp
└── CMakeLists.txt
with CMakeLists.txt containing something like:
//Global
cmake_minimum_required(VERSION 3.22)
project(project-name)
//Repository-wide options
set(CMAKE_CXX_STANDARD 17)
//Local
add_executable(project-root)
target_include_directories(project-name PUBLIC include)
target_include_directories(project-name PRIVATE src)
// Project-specific options
// Assumes gcc/clang toolchain as an example.
target_compile_options(project-name -Wall -Wextra -Werror -pedantic)
target_sources(project-name
PUBLIC
include/project-name/model/foo/a.h
include/project-name/view/c.h
PRIVATE
src/model/foo/b.h
src/model/foo/b.cpp
src/view/c.cpp
src/main.cpp
)
Modern way is to use target_ variants instead of global ones.
If the repository contained more than one project, have one //Global CMakeLists.txt with the three lines above - with global options - and bunch of add_subdirectory calls which each contain //Local CMakeLists.txt for the submodule - executable/library.
a.h,c.h are marked as public, one should always include them with #include <project-name/model/foo/a.h> from anywhere.
I marked b.h as private just for demonstration purposes, there are two ways how to include it. b.cpp could use #include "b.h" or #include "model/foo/b.h" (no <> although it would work). I try to use the latter always apart from b.cpp-b.h declaration-definition pairs. I never use ../ or subdir/b.h since it makes a headache to move anything. This way, each header is included exactly the same way from anywhere - easily searchable and replaceable, b.{cpp,h} move together so the relative path is OK there.
For an executable, I usually just go with all public headers.
If this were a library, it can easily be converted to a e.g. a debian package since one can cleanly install the whole include directory to /usr/include without fear of clashes or hassle to extract the headers from src since src contains only private ones.
You can use cmake builtin variables to construct absolute paths, e.g. PROJECT_SOURCE_DIR.
include_directories(${PROJECT_SOURCE_DIR})
More fine-grained control over includes is possible using target_include_directories.

CMake Windows find_package Imported target "..." includes non-existent path

I am creating my own package that configures, builds and installs the package without problem including cmake files.
The source files are here:
https://github.com/petrasvestartas/CMAKE/tree/main/install_export
Installation procedure build SHARED libs like this:
cmake -DBUILD_SHARED_LIBS=ON -G "Visual Studio 17 2022" -A x64 .. && cmake --build . --config Release && cmake --install .
I see the files here after installation:
C:\ProgramFiles\
│ sortdemo-config-release.cmake
│ sortdemo-config.cmake
│
├───include
│ ├───print
│ │ print.hpp
│ │
│ └───sort
│ sort.hpp
│
└───lib
my_print_lib.dll
my_print_lib.lib
my_sort_lib.dll
my_sort_lib.lib
Now I want to use this package to another simple project:
https://github.com/petrasvestartas/CMAKE/blob/main/find_package/CMakeLists.txt
But I get an error:
Imported target "my_sort_lib" includes non-existent path -> include/sort files
MY SIMPLE QUESTION:
How to know where CMake searches for the files?
Since I have created the project I could modify the path, but I do not know where the problem is.

Build and Link zlib fails because CMake renames files?

I have the following project structure:
project/
├─ CMakeLists.txt
├─ src/
├─ libraries/
│ ├─ directxtk/
│ │ ├─ CMakeLists.txt
│ ├─ zlib/
│ │ ├─ CMakeLists.txt
project/CMakeLists.txt is my main executable. I want to utilize zlib in it.
In this CMakeLists.txt, i have the following lines:
target_include_directories(Project PUBLIC ${EXTERNAL_HEADERS_DIR})
add_subdirectory("${LINK_LIBRARY_DIR}/zlib")
add_subdirectory("${LINK_LIBRARY_DIR}/directxtk")
target_link_libraries(Project LINK_PUBLIC zlib)
target_link_libraries(Project LINK_PUBLIC DirectXTK)
EXTERNAL_HEADERS_DIR and LINK_LIBRARY_DIR both point to Project/Libraries.
I include zlib the following way: #include <zlib/zlib.h>
When I try to build and run now, I receive the following compile error:
...\Project\Libraries\zlib/zlib.h(34): fatal error C1083: Cannot open include file: 'zconf.h': No such file or directory
apparently, CMake seems to rename zconf.h to zconf.h.included!?
How can I properly build this whole thing?
Edit: I have copy&paste'd zlib/CMakeLists.txt from the public website of zlib

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

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.

CMake library dependencies

This may be a tad hard to explain in full. I have setup a directory structure for a series of C++ libraries I am writing. I intend to use CMake to handle building these libraries. For the most part these libraries are completely separate "subsystems" but in the odd places one library needs access to the header file contained within another. Here is my directory structure.
base
├─ cmake
├─ docs
├─ examples
└─ sources
├─ libA
│ ├─ include
│ │ └─ libA
│ │ ├─ core.h
│ │ └─ *.h
│ ├─ source
│ │ └─*.cpp
└─ libB
├─ include
│ └─ libB
│ ├─ message.h
│ └─ *.h
└─ source
└─ *.cpp
There are CMakeLists.txt files in a few places. The main one is within the root directory base which sets up a bunch of variables and options and lastly calls add_subdirectory(sources). Within sources the CMakeLists.txt file simply calls:
add_subdirectory(libA)
add_subdirectory(libB)
Lastly there are CMakeLists.txt files in both the libA and libB directories. These are both largely the same except for the target name. An example of one of these files is:
set(target libA)
# Sources
set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include/${target}")
set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source")
# Add include directories
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
# Set the source files to compile
file(GLOB_RECURSE sources ${source_path}/**/*.cpp)
# Build library
add_library(${target} ${sources})
Now separately both of these libraries can be built without issue but I need to be able to include a header from libA in a source file within libB
// base/sources/libB/source/message.cpp
#include <ctime>
#include <iostream>
#include <libA/core.h>
#include <libB/message.h>
However when I build this I get the following error:
fatal error: 'libA/core.h' file not found
I have tried using target_link_libraries and target_include_directories without any luck. Clearly I am using these wrong or simply don't understand what each of these do.
Since your library libB needs a header from libA to compile, let's say libA is a dependency of libB. Fortunately, CMake is very clever at handling dependencies, so your job is pretty easy:
libA
Instead of
# Add include directories
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
add to the end
target_include_directories(${target} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
This will tell CMake that it must also include the headers for libA to the other projects that need it.
libB
Just tell CMake that libB needs libA:
target_link_libraries(${target} libA)
Note that this doesn't relate directly to the linking step when you compile. For libraries it mainly tells that there is this dependency, and in this case it will automatically add the paths for the headers automatically.
You can add to your CMakeLists.txt for libB, another include directory:
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../libA/include")