This question already has answers here:
Getting base name of the source file at compile time
(12 answers)
Closed 5 years ago.
I use __FILE__ during logging and debug my program. And when I use it, I get full source file path. So, I wanna write my own macro similar the macro __FILE__.
I looked for a solution, but I found nothing about it.
So, does it exist a CMake way to implement user macro, that will be generate something data similar the __FILE__ macro?
Just remove the path from __FILE__.
Possible solution:
#include <libgen.h>
#include <stdio.h>
#define LOG(message) \
do { \
char* filename = basename(__FILE__); \
printf("In %s: %s", filename, message); \
} while(false);
Example has to be extended by check of log level. And instead of a fixed message a variadic number of arguments should be used.
Note: This is for Unix. Assume your OS provides a similar function.
As I mentioned in a comment already, you can create a CMake function that loops over all source files of a given target and adds a macro definition to the compile flags for that source file.
function(add_filepath_macro target)
get_target_property(SOURCE_FILES ${target} SOURCES)
foreach (FILE_PATH IN LISTS SOURCE_FILES)
file(RELATIVE_PATH RELATIVE_FILE_PATH ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${FILE_PATH})
set_property(SOURCE ${FILE_PATH} APPEND PROPERTY COMPILE_DEFINITIONS FILEPATH="${RELATIVE_FILE_PATH}")
endforeach()
endfunction()
This now defines the macro FILEPATH in every TU that is part of the target you pass to it.
There is one caveat though: In contrast to the regular __FILE__ macro you can't use the FILEPATH macro in header files, because including one such header in different translation units immediately causes an ODR violation and thus undefined behaviour.
Demo
Let's see how this works for a very small example. Start with the following project structure:
.
├── cmake
│ └── add_filepath_macro.cmake
├── CMakeLists.txt
├── lib
│ ├── a.cpp
│ ├── a.h
│ └── CMakeLists.txt
└── main.cpp
The cmake/add_filepath_macro.cmake file contains nothing but the code shown above.
The we have the library files
// lib/a.h
#pragma once
char const* foo();
// lib/a.cpp
#include "a.h"
char const* foo() {
return FILEPATH;
}
with corresponding CMakeLists.txt
# lib/CMakeLists.txt
add_library(liba
a.cpp
)
target_include_directories(liba PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
add_filepath_macro(liba)
as well as a small demo executable
// main.cpp
#include <iostream>
#include "a.h"
int main() {
std::cout << foo() << '\n' << FILEPATH << '\n';
}
and finally the project CMakeLists.txt
# CMakeLists.txt
# not tested with older version, but I guess it should work with anything > 3.0
cmake_minimum_required(VERSION 3.9)
project(cmake_filepath_macro_demo LANGUAGE CXX)
include(cmake/add_filepath_macro.cmake)
add_subdirectory(lib)
add_executable(demo
main.cpp
)
add_filepath_macro(demo)
Running the resulting executable then produces the following output
$ ./demo
lib/a.cpp
main.cpp
Related
This question already has answers here:
How to set CMake to have root directory in include paths
(2 answers)
CMake: C++ include relative to base directory
(1 answer)
How to avoid relative paths in include folder
(2 answers)
Closed 4 days ago.
Project Sturcture
I am learning how to build a C++/cmake template. The structure looks like:
.
├── CMakeLists.txt
├── README.md
└── src
├── CMakeLists.txt
└── geometry
├── CMakeLists.txt
└── line
├── CMakeLists.txt
├── line.cpp
└── line.h
Every CMakeLists.txt looks like the following:
./CMakeLists.txt:
cmake_minimum_required(VERSION 3.20.0)
project(cmake_template VERSION 0.0.1 LANGUAGES CXX)
add_subdirectory(src)
./src/CMakeLists.txt:
add_subdirectory(geometry)
./src/geometry/CMakeLists.txt:
add_subdirectory(line)
./src/geometry/line/CMakeLists.txt:
add_library(line line.cpp)
target_include_directories(line PUBLIC .)
And the implementation looks like:
line.h:
#include <string>
class Line{
private:
std::string name;
public:
Line(std::string);
virtual void display();
};
line.cpp:
#include "src/geometry/line/line.h"
#include <iostream>
Line::Line(std::string name):name(name){}
void Line::display(){
std::cout << "A line with name " << this->name << "\n";
}
Compile and error
The command I run is cmake -S . -B build && cmake --build build/, and it shows the error:
[1/2] Building CXX object src/geometry/line/CMakeFiles/line.dir/line.cpp.o
FAILED: src/geometry/line/CMakeFiles/line.dir/line.cpp.o
/usr/bin/clang++ -I../src/geometry/line/. -g -MD -MT src/geometry/line/CMakeFiles/line.dir/line.cpp.o -MF src/geometry/line/CMakeFiles/line.dir/line.cpp.o.d -o src/geometry/line/CMakeFiles/line.dir/line.cpp.o -c ../src/geometry/line/line.cpp
../src/geometry/line/line.cpp:1:10: fatal error: 'src/geometry/line/line.h' file not found
#include "src/geometry/line/line.h"
^~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
ninja: build stopped: subcommand failed.
The code can compile if I change to #include "line.h"
My questions are:
How can I include the absolute path without change the current structure? I.e., I don't want to change CMakeLists.txt in the upper level, only ./src/geometry/line/CMakeLists.txt can be changed.
How can I use <> to include the absolute path? I.e., #include <src/geometry/line/line.h>? The reason of using <> is from the Canonical CPP Project Structure.
I am currently reading "Modern CMake for C++" ([1]) and I am at page 193 where the concept of "position independent code" is explained. However it is only explained in one page and I didn't completely understand what its purpose is exactly and when I need to set it manually. I am still a noob when it comes to the details of how compiling/linking in C++ works, that's part of why I bought this book. It explains the basic concepts of how compilation/linking works in the previous chapters and I felt like I understood those concepts fairly well (how static libraries are basically archived object files and shared libraries being similar to final executables that can be loaded into runtime dynamically, for example). However, I am not sure how "position indenpendent code" fits in here, or, in other words, I am not sure if I understood it correctly.
From what I have read ([2], [3]) my current understanding is this:
Static libraries produce position dependent (machine) code by default. Their variables are
mapped to hardcoded virtual memory addresses which is more efficient.
Shared libraries produce position independent machine code. Since they are dynamically loaded into the process runtime, it can't be known to which address their variables will be mapped to. For this purpose, they have a global offset table that acts as a placeholder address that will be resolved to some spot in the virtual memory when they are executed
When a static library is linked to a shared library, it itself must also be position independent, otherwise... (I don't actually know what would happen otherwise. The book I read just says "you'll run into trouble with CMake" but I don't know what that means).
Please tell me if there is anything wrong in that explanation.
So, let's look at an example project that looks like this:
example/
└── src
├── CMakeLists.txt
├── hiprinter
│ ├── CMakeLists.txt
│ ├── hiprinter.cpp
│ ├── hiprinter.h
│ └── printer
│ ├── CMakeLists.txt
│ ├── printer.cpp
│ └── printer.h
├── prog
│ ├── CMakeLists.txt
│ └── main.cpp
└── warning_props.cmake
Content of the files (from top to bottom):
# src/CMakeLists.txt
cmake_minimum_required(VERSION 3.25)
project(Prog LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
include(warning_props.cmake)
add_subdirectory(prog)
add_subdirectory(hiprinter)
# Create Graphviz Tree visualizing dependencies
add_custom_target(graphviz ALL
COMMAND ${CMAKE_COMMAND} "--graphviz=dtree.dot" .
COMMAND dot -Tpng dtree.dot -o dtree.png
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
)
# src/hiprinter/CMakeLists.txt
add_subdirectory(printer)
add_library(hiprinter STATIC hiprinter.cpp)
target_include_directories(hiprinter PRIVATE .)
target_link_libraries(hiprinter PRIVATE printer warning_props)
// src/hiprinter/hiprinter.cpp
#include "hiprinter.h"
#include "printer/printer.h"
#include <iostream>
void printHi()
{
print("hi");
}
// src/hiprinter/hiprinter.h
#pragma once
void printHi();
# src/hiprinter/printer/CMakeLists.txt
add_library(printer SHARED printer.cpp)
target_include_directories(printer PRIVATE .)
target_link_libraries(printer PRIVATE warning_props)
// src/hiprinter/printer/printer.cpp
#include "printer.h"
#include <iostream>
#include <string>
void print(std::string s)
{
std::cout << s << std::endl;
}
// src/hiprinter/printer/printer.h
#pragma once
#include <string>
void print(std::string s);
# src/prog/CMakeLists.txt
add_executable(Prog main.cpp)
target_link_libraries(Prog PRIVATE hiprinter warning_props)
target_include_directories(Prog PRIVATE ..)
// src/prog/main.cpp
#include "hiprinter/hiprinter.h"
int main()
{
printHi();
}
# src/warning_props.cmake
add_library(warning_props INTERFACE)
# Enable ALL warnings and treat them as errors
target_compile_options(warning_props INTERFACE
-Wall
-Wextra
-Wpedantic
-Werror
)
GraphViz dependency tree:
Prog depends on hiprinter, a static library. Since hiprinter itself is static and it depends on a shared library, printer, according to the reasons stated above, I would have to configure hiprinter as position-independent right? Because it is a static library and is position-dependent by default.
So, I'd have to edit src/hiprinter/CMakeLists.txt like this:
# src/hiprinter/CMakeLists.txt
add_subdirectory(printer)
add_library(hiprinter STATIC hiprinter.cpp)
target_include_directories(hiprinter PRIVATE .)
target_link_libraries(hiprinter PRIVATE printer warning_props)
# Add this:
set_target_properties(hiprinter
PROPERTIES POSITION_INDEPENDENT_CODE
ON
)
Am I doing this right?
Also, are there any mistakes in my "explanation" above?
By the way, this project compiles fine with or without the addition for the PIC property. (I am on Ubuntu 20.04, using GCC 10.3.0)
PS: Another question: If a static library depends on another static library that is PIC, the first static library must also be configured as PIC, right?
1 https://en.wikipedia.org/wiki/Position-independent_code
2 GCC -fPIC option
3 Combining CMake object libraries with shared libraries
For my research project I am setting up a project (coom) to benchmark a set of algorithms on a data structure. For unit testing I settled on Bandit, which leaves me with a project structure that looks as follows:
+ root
|-- CMakeLists.txt
|-+ external/
| \-- bandit/
|-+ src/
| |-- CMakeLists.txt
| |-- node.cpp
| \-- node.h
\-+ test/
|-- CMakeLists.txt
|-- test.cpp
\-- test_node.cpp
From my experience with other languages, this seems to me a standard project structure? The test/ folder contains unit tests for the logic in src/ and no dependencies are intermixed with the source and test code, but are instead in external/.
The testing files I want to look as follows (with irrelevant parts removed)
// test/test.cpp
#include <bandit/bandit.h>
(...)
#include "test_node.cpp"
int main(int argc, char* argv[]) {
(...)
}
// test/test_node.cpp
#include <coom/node.h>
(...)
But my problem is, that when I try to compile with cmake .. and the subsequent Makefile, they are unable to find the source code in src/ where I get the compiler error:
fatal error: coom/node.h: No such file or directory.
I would expect the test/CMakeLists.txt should look somewhat like the following:
# test/CMakeLists.txt
add_executable (test_unit test.cpp)
target_link_libraries(test_unit coom)
I cannot figure out how to setup the CMakeLists.txt and src/CMakeLists.txt to ensure I get the desired outcome above. Currently they look as follows:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project (coom VERSION 0.1)
# ============================================================================ #
# Dependencies
(...)
# ============================================================================ #
# COOM project
add_subdirectory (src)
add_subdirectory (test)
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
node.h
)
set(SOURCES
node.cpp
)
add_library(coom ${HEADERS} ${SOURCES})
I can see from other projects, that it is possible to link the src/ directory with some libname/ prefix, but I cannot discern from their CMakeLists.txt files what I am doing wrong. I have looked at writing a coom.pc.in file and providing an install-target, and tried to set_target_properties with either FOLDER coom or PREFIX coom, but neither worked. I can hack an include_directory(../src) into the test/CMakeLists.txt to be able to include the file via an #include <node.cpp>, but that screams I'm doing something inherently wrong.
I'm at this point very much pulling my hairs out, and the CMake documentation is of very little help to me.
Your coom target has no include directories defined. You can define the include directories to use for this target (with target_include_directories()), and propagate these include directories so they are visible to the consuming test_unit target (by using PUBLIC):
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
node.h
)
set(SOURCES
node.cpp
)
add_library(coom ${HEADERS} ${SOURCES})
target_include_directories(coom PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Furthermore, the file path to the node.h header is coom/src/node.h, not coom/node.h. But, because you now have coom/src as an public include directory, you can use the following to include the node.h header in your test file:
#include <node.h>
This question already has answers here:
Linking Rust application with a dynamic library not in the runtime linker search path
(3 answers)
How do I specify the linker path in Rust?
(3 answers)
Where should I place a static library so I can link it with a Rust program?
(3 answers)
Closed 2 years ago.
I have written a C++ library with a C wrapper and want to call those functions from my Rust project. However, when I try to link my Rust project to the C library, I get a long error with the note
note: /usr/bin/ld: cannot find -l../cpp_library/build/libdisplay.so
I have tried passing an absolute path to the library and received a similar error.
My combined project has the following directory and contents
├── cpp_library
│ ├── CMakeLists.txt
│ ├── include
│ │ └── display.h
│ └── src
│ ├── display.cpp
│ └── main.cpp
└── rust_project
├── build.rs
├── Cargo.lock
├── Cargo.toml
├── src
└── main.rs
CMakeLists.txt
cmake_minimum_required(VERSION 3.1.0)
project(directory_test)
set(CMAKE_BUILD_TYPE Release)
#Bring the headers into the project
include_directories(include)
set(SOURCES "src/display.cpp")
#Generate the shared library from the sources
add_library(display SHARED ${SOURCES})
add_executable(display_test "src/main.cpp" ${SOURCES})
display.h
extern "C" {
void display();
}
display.cpp
#include <iostream>
#include "display.h"
void display(){
std::cout << "A C++ println" << std::endl;
}
main.cpp
#include "display.h"
int main() {
display();
}
build.rs
fn main() {
println!("cargo:rustc-link-search=../cpp_library/build/");
println!("cargo:rustc-link-lib=../cpp_library/build/libdisplay.so");
}
main.rs
extern {
fn display();
}
fn main() {
println!("Hello, world!");
unsafe {
display();
}
}
You can also see the project on Github.
I build the C library with
cd cpp_library
mkdir build
cd build
cmake ..
make
When I build the Rust project, I get the error shown above.
How am I supposed to link the C library to the Rust project?
Update 1
The posts How do I specify the linker path in Rust? and Where should I place a static library so I can link it with a Rust program? indicate how to add a directory to the library search path and link a library. I have tried these solutions, but still receive the error mentioned above.
Following the advice of Linking Rust application with a dynamic library not in the runtime linker search path, I compiled the rust project with
cargo rustc -- -C link-args='-Wl,-rpath,$ORIGIN/../../../cpp_library/build/'
but received the same error. I also tried passing an absolute path and received the same result.
I removed the redundant #[link(name = "display")], but this did not resolve the problem.
I am stuck in CMake dependency issue. CMake does not rebuild the program when I modified the CXX header files.
My file structure is as such
$ tree
.
├── a
│ ├── a.h
│ └── c.h
├── b
│ ├── b.h
│ └── c.h
├── CMakeLists.txt
└── main.cxx
File contents:
a.h
$ cat a/a.h
#include "c.h"
b.h
$ cat b/b.h
#include "c.h"
main.cxx
$ cat main.cxx
#include "a/a.h"
#include "b/b.h"
int main()
{
}
CMake depend.internal
$ cat CMakeFiles/hello.dir/depend.internal
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.7
CMakeFiles/hello.dir/main.cxx.o
/proj/mtk09331/work/tmp/cmake/a/a.h
/proj/mtk09331/work/tmp/cmake/a/c.h
/proj/mtk09331/work/tmp/cmake/b/b.h
/proj/mtk09331/work/tmp/cmake/main.cxx
CMakeLists.txt:
$ cat CMakeLists.txt
add_executable(hello main.cxx)
As you can see, b/c.h does not exist in the dependency list.
Therefore, CMake won't rebuild the program if I modified b/c.h.
Does cmake not allow the same header file names?
Altough it works with renaming the header files.
But I would like to find a "correct" way to prevents this.
Thanks in advance
As #MABVT notes in the comment, CMake is unrelated here: the question is about proper projects' organization.
From the point of projects' organization, headers for every project can be devided into two parts:
private headers, which are used only for compile the project itself,
public headers, which are used by the outer world (by other projects).
Naming and organization of private headers are fully up to the project's author.
But for scalable projects naming and organization of their public headers should follow several rules:
Name of the public header should be unique among all projects.
Usually this is achived by moving these headers into the directory contained the name of the project.
Public header shouldn't include private header.
Public header should include other public header using only its unique name.
As you can see, headers a/a.h and b/b.h are public in your case.
But for headers a/c.h and b/c.h you should decide, whether they are public or private.
If you want to make a/c.h private, then public header a/a.h cannot include it (rule 2).
If you want to make a/c.h public, then public header a/a.h should include it using its unique name, that is #include <a/c.h> (rule 3).
This appears to be a feature of make. As stated by #Tsyvarev, adding the sub-directory name in the #include statement helps make find the correct dependencies but looks awkward in the source code.
ninja correctly determines the dependencies in the case above. To use with cmake install ninja and select it with ...
cmake -G Ninja