I am trying to code a little C++ program, where I access a sensor through a C hardware library (the bmp280 in this example). For some reasons that are not important right now, I want to compile the measurement code firstly to a shared library (for Linux, therefore a libXXX.so file) and afterwards include the resulting library in a test executable. With the following CMakeLists I am actually able to compile the library target itself (wsh), but not the executable depending on it (main).
project(weather-station-hardware-driver)
message(STATUS "Selected C Compiler: ${CMAKE_C_COMPILER}")
message(STATUS "Selected C++ Compiler: ${CMAKE_CXX_COMPILER}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set(CMAKE_CXX_STANDARD 20)
include(FetchContent)
FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.1/json.tar.xz)
FetchContent_Declare(bmp2 GIT_REPOSITORY https://github.com/BoschSensortec/BMP2-Sensor-API.git)
FetchContent_MakeAvailable(json bmp2)
add_library(wsh SHARED src/library.cpp src/bmp280.cpp src/bmp280.hpp)
set_target_properties(wsh PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(wsh PUBLIC i2c)
target_include_directories(wsh PUBLIC ${bmp2_SOURCE_DIR})
add_executable(main src/main.cpp)
target_link_libraries(main PRIVATE wsh nlohmann_json::nlohmann_json)
The result is the following error message:
: && /usr/bin/c++ -g CMakeFiles/main.dir/src/main.cpp.o -o ../bin/main -Wl,-rpath,/home/fabro122/workspace/intellij/weather-station-webserver/native/hardware-driver/bin ../bin/libwsh.so -li2c && :
/usr/bin/ld: ../bin/libwsh.so: undefined reference to `bmp2_get_config'
/usr/bin/ld: ../bin/libwsh.so: undefined reference to `bmp2_init'
where bmp2_get_config
and bmp2_init
are c functions from the source files in ${bmp2_SOURCE_DIR}
.
I already tried to add the following line:
target_link_directories(wsh PUBLIC ${bmp2_SOURCE_DIR})
And to include the headers from the library as C code (which should be unnecessary, because the bmp280 source file includes a "cpp guard" anyways):
extern "C" {
#include <bmp2.h>
}
And also to compile directly to the executable -> without compiling and linking my own shared library first.
Nothing helped and couldn't find any other tips on stackoverflow, so here I am, hoping for help. Thanks in advance!
Here are the other relevant source files (excluding the .hpp files):
main.cpp
#include <iostream>
#include <nlohmann/json.hpp>
#include "library.hpp"
using namespace std;
using namespace wsh;
namespace wsh {
// The non-intrusive macro is used to avoid the shared library depending on nlohmann/json.hpp
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Measurement, temperature, pressure, humidity, airQuality, ambientLight)
}
int main() {
Measurement data = doMeasurement();
nlohmann::json j = data;
cout << j << endl;
return 0;
}
library.hpp
#include "library.hpp"
#include "bmp280.hpp"
wsh::Measurement wsh::doMeasurement() {
auto allData = Measurement();
bmp280 bmp;
return allData;
}
bmp280.cpp
#include "bmp280.hpp"
#include <bmp2.h>
namespace wsh {
BMP2_INTF_RET_TYPE i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t length, void* intf_ptr) {
return 0;
}
BMP2_INTF_RET_TYPE i2c_write(uint8_t reg_addr, const uint8_t* reg_data, uint32_t length, void* intf_ptr) {
return 0;
}
bmp280::bmp280() {
// device and address are defined in .hpp
device.chip_id = address;
device.intf = BMP2_I2C_INTF;
device.read = i2c_read;
device.write = i2c_write;
bmp2_init(&device);
// configure
bmp2_config conf{};
bmp2_get_config(&conf, &device);
}
}