I created a simple cmake project to reproduct it.
├── CMakeLists.txt
├── lib1
│ ├── CMakeLists.txt
│ ├── lib1.cpp
│ └── lib1.h
├── lib2
│ ├── CMakeLists.txt
│ ├── lib2.cpp
│ └── lib2.h
└── main.cpp
lib1/CMakeLists.txt:
add_library(lib1 "")
target_include_directories(lib1
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
target_sources(lib1
PRIVATE
lib1.cpp
lib1.h
)
In lib1.cpp, there is a function "void say()":
#include <stdio.h>
void say()
{
printf("hello from lib1\n");
}
lib2/CMakeLists.txt:
add_library(lib2 "")
target_include_directories(lib2
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
target_sources(lib2
PRIVATE
lib2.cpp
lib2.h
)
And in lib2/lib2.cpp, there is a function of the same signature:
#include <stdio.h>
void say()
{
printf("hello from lib2\n");
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(shell LANGUAGES CXX)
add_subdirectory(lib1)
add_subdirectory(lib2)
add_executable(test2
main.cpp
)
target_link_libraries(test2
PRIVATE
lib1
lib2
)
Here is the main.cpp:
void say();
int main()
{
say();
return 0;
}
The output:
hello from lib1
There is no compile or link error, not even a warning.
The linker just picked one and symply ignored the other one.
I'm using cmake 3.16, and tested it with msvc 2017/2019 and g++ 7.5.
How to make the linker prompts errors when there are symbol conflicts in static libraries?
Thanks!
How to make the linker prompts errors when there are symbol conflicts in static libraries?
With gcc use the --whole-archive option to include every object file in the archive rather then search the archives for the required symbol.
As there is no cmake support that I know of, I find it's typically done when linking the executable:
target_link_libraries(test2 PRIVATE
-Wl,--whole-archive
lib1
lib2
-Wl,--no-whole-archive
)
"Symbol conflicts" is rather vague term. This will only detect multiple symbol definitions. Types of symbols are not stored anywhere after compilation.
Related
In a c++ CMake project I have an executable main and two libraries lib1 and lib2. A function in lib1 needs a function from lib2 and visa versa. Also, lib1 only contains .h files. The main executable will use both libraries. When I try and "make" the project, I get an error:
error: redefinition of ‘void lib1()’.
The file structure looks somewhat like this
/path/to/my/project
├── CMakeLists.txt # Project directory
├── main.cpp
├── Lib1
│ ├── ...files (.h only)...
│ ├── CMakeLists.txt # lib1 cmake
├── Lib2
│ ├── ...source files (.cpp & .h)...
│ ├── CMakeLists.txt # lib2 cmake
The CMakeLists.txt in the Project directory includes the following:
add_executable(${PROJECT_NAME} main.cpp)
add_subdirectory(Lib1)
add_subdirectory(Lib2)
target_link_libraries(${PROJECT_NAME}
lib2
lib1
)
The CMakeLists.txt in the Lib1 directory includes the following:
add_library(lib1 INTERFACE)
target_include_directories(lib1
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(lib1 INTERFACE
lib2
)
The CMakeLists.txt in the Lib2 directory includes the following:
add_library(lib2 ${SOURCES} ${HEADERS}) # SOURCES and HEADERS set in lines above
target_include_directories(lib2
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(lib2
lib1
)
If I had to guess, the issue is it is trying to import lib1 headers twice. Once from lib2 and once in my main executable. How do I link the libraries so that isn't an issue?
I dont think it's anything related to cmake. Although convoluted (I'd do it in another way but hey it's your code) I think you are defining the body of a function in lib1 where it should reside in a cpp file.
Make that function lib1 inline.
inline void lib1() {
...
}
or alternatively defined it in the header and implement it in a body file
//lib1.h
void lib1();
Then
//lib1.cpp
#include "lib1.h"
void lib1() {
...
}
I'm working on an hobby project in C++, using flex and bison. I'm using CMake as my build system, and I had struggle in making all work together.
I'm quite new to CMake so the documentation seems quite minimal to me. It is showed how to link everything in one executable.
But I'm trying to keep all the parts of my code separated, so I would like to have my flex/bison file in a subfolder. My structure is this:
.
├── build
| └-- ...
├── CMakeLists.txt
├── flexbison
│ ├── CMakeLists.txt
│ ├── lexer.ll
│ └── parser.yy
├── lib
│ ├── CMakeLists.txt
│ └── ...
├── main.cpp
└── run.sh
So I want to have my yyparse function separate from my main.cpp, as well as my other C++ files. I managed to get it done in this way:
project_root/CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(progetto-di-prova VERSION 0.1)
add_subdirectory(flexbison)
add_executable(executable main.cpp)
target_include_directories(executable PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_BINARY_DIR}/flexbison"
)
set_target_properties(executable PROPERTIES CXX_STANDARD 11)
target_link_libraries(executable parserlib)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
flexbison/CMakeLists.txt:
find_package(FLEX)
find_package(BISON)
flex_target(lexer lexer.ll "${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp")
bison_target(parser parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp
DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/parser.h)
add_flex_bison_dependency(lexer parser)
add_library(parserlib STATIC
${FLEX_lexer_OUTPUTS}
${BISON_parser_OUTPUTS}
)
the main.cpp file:
#include <parser.h> // <-this was the line causing troule
#include <iostream>
extern int yylex(void);
int main(int argc, char *argv[])
{
yyparse();
return 0;
}
Now, the point is: is this the correct way of doing so? Is it better to put the main function in the bison code?
My main problem, as highlighted in the code, was to include the parser.h header file in the main.cpp. Is this the CMake-way to do it?
Thanks in advance!
If I were you I would have:
flexbison/CMakeLists.txt:
...
add_library(parserlib STATIC
${FLEX_lexer_OUTPUTS}
${BISON_parser_OUTPUTS}
)
target_include_directories(parserlib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<INSTALL_INTERFACE:include/parserlib> # <prefix>/include/parserlib
)
note: $<INSTALL_INTERFACE:include/parserlib> need to be adapted if you want and how you install parserlib...
project_root/CMakeLists.txt:
...
target_include_directories(executable PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
...
Since executable is "target_link" against parserlib which provides public include directories, you don't need to list these directories anymore in executable's include dirs.
ref: https://cmake.org/cmake/help/latest/command/target_include_directories.html
After reading some articles on static and shared libs I think I know the difference but I still cannot figure out a way to fix my use case. I have the following project structure
Project
├── A
│ ├── A.cpp
│ ├── A.h
│ └── CMakeLists.txt
├── B
│ ├── CMakeLists.txt
│ └── B.cpp
├── CMakeLists.txt
in folder A I have:
//content of A.h
#include <opencv2/opencv.hpp>
cv::Mat A_load_image(std::string file_path);
//content of A.cpp
#include "A.h"
cv::Mat A_load_image(std::string file_path) {
return cv::imread(file_path);
}
// content of CMakelists.txt in A
set(TARGET A)
add_library( ${TARGET} STATIC A.cpp )
target_include_directories(${TARGET} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
/path/to/opencv/include/folder )
link_directories( /path/to/opencv/lib/folder)
target_link_libraries( ${TARGET} PUBLIC libopencv_core.a )
then in my folder B I have:
//content of B.cpp
#include "A.h"
cv::Mat B_load_image() {
return A_load_image("img.bmp");
}
// content of CMakelists.txt in B
set(TARGET B)
add_library(A STATIC IMPORTED)
set_target_properties(A PROPERTIES IMPORTED_LOCATION /PATH/TO/libA.a)
add_library(${TARGET} SHARED B.cpp)
target_include_directories(${TARGET} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../A
/path/to/opencv/include/folder )
target_link_libraries(${TARGET} PUBLIC A libopencv_core.a)
And of course I have the CMakelists.txt file in the project root has:
cmake_minimum_required(VERSION 3.4.1)
add_subdirectory(B)
add_subdirectory(A)
I have questions below regarding this project.
How to tell cmake to compile B first so that when I import B for A, it is already updated if any changes
The above setup does not work as I got error when linking B: "cannot find -lopencv_core", I already used PUBLIC for linking A, I also tried to add link_directories( /path/to/opencv/lib/folder) to the CMakelists.txt for B, but still not working.
I believe "cannot find -lopencv_core" failed because it is looking for dynamic lib, e.g., libopencv_core.so rather than the static one. But why is that and how I force to link to the static lib?
Try an object library:
cmake_minimum_required(VERSION 3.11)
add_subdirectory(A)
add_subdirectory(B)
# A/CMakeLists.txt
find_package(OpenCV REQUIRED)
add_library(A OBJECT A.cpp)
target_include_directories(A PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(A PUBLIC ${OpenCV_LIBS})
# B/CMakeLists.txt
add_library(B SHARED B.cpp)
target_include_directories(B PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(B PUBLIC A)
# also try
target_link_options(B PRIVATE "-Wl,--whole-archive")
# or maybe
target_link_options(B PRIVATE "-Wl,--export-all-symbols")
# or maybe also
target_sources(B $<TARGET_OBJECTS:A>)
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 successfully played trial-and-error with a CMakeLists.txt file, and now everything builds. However, I want to make sure my understanding is correct about how it's working.
I have a project with the following structure:
./
├── bin
├── CMakeLists.txt
├── include
│ └── sql-writer
│ ├── credentials.h
│ ├── database.h
│ ├── datetime.h
│ ├── market_bar.h
│ └── writer.h
├── README.md
├── src
│ ├── CMakeLists.txt
│ ├── database.cpp
│ ├── main.cpp
│ └── writer.cpp
└── test
├── CMakeLists.txt
├── test-main.cpp
├── test_sym_table_pairs
└── writer_tests.cpp
This builds an executable, a static library, and a test executable. The problem was src/CMakeLists.txt:
set(HEADER_DIR ${sql-writer_SOURCE_DIR}/include/sql-writer)
add_executable(sql-writer-demo main.cpp ${HEADER_DIR})
target_include_directories(sql-writer-demo PUBLIC ${HEADER_DIR}) #!
target_link_libraries(sql-writer-demo sql-writer-lib mysqlcppconn ${Boost_LIBRARIES})
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp)
file(GLOB HEADERS ${HEADER_DIR}/*.h)
add_library(sql-writer-lib ${HEADERS} ${SOURCES})
target_link_libraries(sql-writer-lib mysqlcppconn ${Boost_LIBRARIES})
target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR})
the first line's set command just defines HEADER_DIR. This is easy.
target_include_directories(sql-writer-demo PUBLIC ${HEADER_DIR}) must be included after the first add_execuable because otherwise header files will need to be included with relative paths. Is that right? Why does it come after? I've heard cmake treats include directories as "separate" from "sources" (cmake sources not .cpp files). What does that mean?
target_link_libraries(sql-writer-demo sql-writer-lib mysqlcppconn ${Boost_LIBRARIES}) needs to come after add_executable(sql-writer-demo main.cpp ${HEADER_DIR}) as well, and it tells how to link to other libraries.
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp) is not recomended before only because the directory/file structure could change, and then this wouldn't work anymore
target_link_libraries(sql-writer-lib mysqlcppconn ${Boost_LIBRARIES}) needs to come after add_library(sql-writer-lib ${HEADERS} ${SOURCES}) because the compulation of my library sql-writer-lib needs to use other libs, and this is where we tell cmake to look out for those.
You typically don't include headers into add_executable and add_library, but only implementation files:
add_executable(sql-writer-demo main.cpp)
add_library(sql-writer-lib ${SOURCES})
add_executable and add_library create a target, target_include_directories specifies include directories for this target. The documentation is pretty clear:
The named <target> must have been created by a command such as add_executable() or add_library() and must not be an IMPORTED target.
If you use target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR}) with PUBLIC specifier, you don't need to use target_include_directories to specify include directories for targets that link against that library, because the dependency will be propagated automatically. The same applies to target_link_libraries.
So, src/CMakeLists.txt
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp)
add_library(sql-writer-lib ${SOURCES})
target_link_libraries(sql-writer-lib PUBLIC mysqlcppconn ${Boost_LIBRARIES})
target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR})
add_executable(sql-writer-demo main.cpp)
target_link_libraries(sql-writer-demo sql-writer-lib)
should work. Whether you want to use PUBLIC on mysqlcppconn ${Boost_LIBRARIES} depends on the structure of your project. I specified it as an example only.