Linker error because of unresolved symbols from QtRemoteObjects replica definitions - c++

I am working on the project which uses Qt Remote Objects and I wanted to test one of my components using auto-generated ReplicaDefSimpleSource class (see the example below for the details). However, when I tried to link test executable with my library, I got the following linker error:
main.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const ReplicaDefSimpleSource::staticMetaObject" (?staticMetaObject#ReplicaDefSimpleSource##2UQMetaObject##B)
I checked my MyLib.dll with DependencyWalker, the required symbol is there:
79 (0x004f), 78 (0x0000004e), public: static struct QMetaObject const ReplicaDefSimpleSource::staticMetaObject, 0x00018370, Microsoft
I also checked dumpbin /EXPORTS Debug/MyLib.lib | grep "static struct QMetaObject", and again the required symbol is there:
?staticMetaObject#ReplicaDefSimpleSource##2UQMetaObject##B (public: static struct QMetaObject const ReplicaDefSimpleSource::staticMetaObject)
To build the project I used CMake:
cmake -G "Visual Studio 15 2017 Win64" ../
cmake --build . --config Debug
To reproduce the problem you need the following files:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.11)
project(test_project)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set (CMAKE_CXX_STANDARD 17)
find_package(Qt5 COMPONENTS
Core REQUIRED
RemoteObjects REQUIRED
Test REQUIRED
)
qt5_generate_repc(GENERATED ReplicaDef.rep SOURCE)
qt5_generate_repc(GENERATED ReplicaDef.rep REPLICA)
set_source_files_properties(${GENERATED} PROPERTIES GENERATED TRUE SKIP_AUTOMOC TRUE)
add_library(MyLib SHARED a.cpp ${GENERATED})
set_target_properties(MyLib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
target_link_libraries(MyLib
Qt5::Core
Qt5::RemoteObjects
)
add_executable(main main.cpp
# moc_rep_ReplicaDef_source.cpp
)
target_link_libraries(main MyLib Qt5::Test)
main.cpp: yep, I know it is not how you are supposed to test Qt code, I just use it as minimal example (e.g. it doesn't have QApplication)
#include "rep_ReplicaDef_source.h"
#include <QTest>
#include <QSignalSpy>
#include <QUrl>
#include <memory>
void foo();
int main()
{
foo(); // here no problem with linker
ReplicaDefSimpleSource source;
QRemoteObjectHost host;
host.setHostUrl(QUrl{ "local:main" });
host.enableRemoting(&source);
// QSignalSpy is using staticMetaObject that linker complains about
QSignalSpy spy(&source, &ReplicaDefSimpleSource::settingsChanged);
spy.wait(1000);
return 0;
}
ReplicaDef.rep:
#include <QtCore>
#include <QString>
class ReplicaDef
{
PROP(QString settings);
};
a.cpp: it actually can be anything, I just put there some dummy function to show that the symbols from a.cpp are visible
#include <iostream>
void foo() { std::cout << "foo" << std::endl; }
As a workaround I can just explicitly include auto-generated sources in my test, but this is not acceptable solution.
add_executable(main main.cpp
moc_rep_ReplicaDef_source.cpp
)
The provided example of course compiles and works on any normal system, I just have the problem on windows, which I am forced to use (sorry for asking a question about this platform).
What should I do to test my system using auto-generated replica classes and without compiling their sources multiple times?
As a side question: why the linker does not complain about multiple definitions if I include the replica sources in main executable?
=== EDIT ===
Just to make sure that nothing weird happens when I compile Qt autogenerated code with my hand-written code, I tried to put replica sources in a separate library:
qt5_generate_repc(GENERATED ReplicaDef.rep SOURCE)
qt5_generate_repc(GENERATED ReplicaDef.rep REPLICA)
set_source_files_properties(${GENERATED} PROPERTIES GENERATED TRUE SKIP_AUTOMOC TRUE)
add_library(MyLib-replica SHARED ${GENERATED})
target_link_libraries(MyLib-replica
Qt5::Core
Qt5::RemoteObjects
)
set_target_properties(MyLib-replica PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(MyLib SHARED a.cpp)
set_target_properties(MyLib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
target_link_libraries(MyLib
MyLib-replica
)
but the problem remains the same. Missing symbols if I do not include autogenerated sources explicitly in each target.

Related

Crosscompiling cpp Shared Object results in "Undefined Symbol" but works for c Setup

I want to crosscompile a shared library (c and cpp code) on my Ubuntu System (x86_64) for Android aarch64. For reasons of simplicity for this example I created only a source and a header file.
The header file header.hpp within /include
int test();
The source file src.cpp within /src
#include "../include/header.hpp" // #include "../include/header.h"
int test() {
return 42;
}
My CMakeLists.txt
cmake_minimum_required(VERSION 3.6.0)
set(CMAKE_TOOLCHAIN_FILE android.toolchain.cmake)
project(testlibrary)
# find header & source
file(GLOB_RECURSE SOURCE_CPP "src/*.cpp")#file(GLOB_RECURSE SOURCE_C "src/*.c")
file(GLOB_RECURSE HEADER "include/*.h")
add_library(${PROJECT_NAME} SHARED
${SOURCE_CPP}
${HEADER}
)
My android.toolchain.cmake
cmake_minimum_required(VERSION 3.6.0)
set(CMAKE_CXX_COMPILER "/usr/bin/aarch64-linux-gnu-g++")#set(CMAKE_C_COMPILER "/usr/bin/aarch64-linux-gnu-gcc")
set(CMAKE_ANDROID_NDK /home/ubuntu/Android/Sdk/ndk/21.4.7075529)
After calling my function within my app I receive the following error message:
Could not invoke FunctionCaller.test_function
null
Error looking up function 'testFunc': undefined symbol: testFunc
Not finding testFunc seems to be related to not compiling or correctly linking my .cpp/.hpp files I suppose.
Changing my setup from cpp to c and everything is found and I receive the correct return value.
C++
C
src.cpp
src.c
header.hpp
header.c
#include "../include/header.hpp"
#include "../include/header.h"
file(GLOB_RECURSE SOURCE_CPP "src/*.cpp")
file(GLOB_RECURSE SOURCE_C "src/*.c")
set(CMAKE_CXX_COMPILER "/usr/bin/aarch64-linux-gnu-g++")
set(CMAKE_C_COMPILER "/usr/bin/aarch64-linux-gnu-gcc")
What am I missing here? I expected it to fail for both configurations since I installed both compilers the same way.

C++ function not exported by .so seemingly because of pybind11 parameters

I am currently trying to define a shared library that I aim to use from a Python C++ extension as well as from vanilla C++ applications.
I managed to build the shared library, and tried to link a simple C++ application against it to test its functionalities, but one of the functions of the shared library is treated as an undefined reference by the linker. After checking with nm --demangle --dynamic --defined-only --extern-only libmylib.so, I realized the function is not being exported by the shared library, but I have no idea why.
The function's signature is as follows:
void bootstrap_mylib(std::vector<std::string> python_path,
std::vector<std::string> python_scripts,
std::string interface_module,
std::function<void (pybind11::module_, pybind11::object)> interface_module_initializer);
Everything goes well if I comment out the last parameter, so the problem seems to be coming from the way I declare the dependencies with pybind11 somehow.
Here are the relevant parts of my CMakeLists.txt:
set(CMAKE_CXX_COMPILER /usr/bin/g++)
project(monilog LANGUAGES CXX VERSION 0.0.1)
set(PYBIND11_PYTHON_VERSION 3.8)
find_package(pybind11 REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
add_library(mylib SHARED MyLib.cc MyLib.h)
set_property(TARGET mylib PROPERTY CXX_STANDARD 17)
target_link_libraries(mylib ${PYTHON_LIBRARIES})
set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties(mylib PROPERTIES SOVERSION 1)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER MyLib.h)
Any idea of what I might be doing wrong?
Edit: minimal working example
Here is a minimal example of my problem, consisting of the following files:
example.h
#include <pybind11/stl.h>
namespace Example
{
void simple_func(std::string some_string);
void pybind11_func(pybind11::function some_func);
}
example.cc
#include "example.h"
namespace Example
{
void simple_func(std::string some_string)
{
std::cout << "Simple function" << '\n';
}
void pybind11_func(pybind11::function some_func)
{
std::cout << "Pybind11 function" << '\n';
}
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
cmake_policy(SET CMP0074 NEW)
# SET VARIABLES
set(CMAKE_CXX_COMPILER /usr/bin/g++)
set(CMAKE_CXX_STANDARD 17)
project(example CXX)
set(PYBIND11_PYTHON_VERSION 3.8)
find_package(pybind11 REQUIRED)
# include_directories(${PYTHON_INCLUDE_DIRS})
include_directories(${pybind11_INCLUDE_DIRS})
add_library(example SHARED example.cc example.h)
target_link_libraries(example ${PYTHON_LIBRARIES})
When I build the project, if I then search for func in the exposed symbols, I get the following result:
> nm -D libexample.so | grep "func"
00000000000039d9 T _ZN7Example11simple_funcENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
pybind11_func is thus not exported, while simple_func is correctly exported.
Namespace pybind11 has hidden visibility.
/usr/include/pybind11/detail/common.h:#
define PYBIND11_NAMESPACE pybind11 __attribute__((visibility("hidden")))
so all functions that have anything to do with that namespace (like having an argument type from it) are also hidden.
You can override this by explicitly setting visibility to default:
__attribute__((visibility("default")))
void bootstrap_mylib( ... )

Cannot find directory in context of main.cpp (Allegro with CMake)

I'm trying to create a library that links against allegro5 media library using CMake. And then, I want to use my library in an executable.
My directory structure is:
src
|----core
|------src
|------tests
|------CMakeLists.txt
|----main.cpp
|----CMakeLists.txt
The CMakeLists.txt file inside the core folder is:
set(MY_HEADERS #My header files here)
set(MY_SRC #My source files here)
add_library(MyLib ${MY_HEADERS} ${MY_SRC})
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
## Allegro Lib
set(ALLEGRO_DIR "${PROJECT_SOURCE_DIR}/packages/allegro5/include")
if(WIN32)
file(GLOB ALLEGRO_LIB "${PROJECT_SOURCE_DIR}/packages/allegro5/windows/x86/lib/*.lib")
add_library(Allegro SHARED IMPORTED)
set_target_properties(Allegro PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${ALLEGRO_DIR}
IMPORTED_IMPLIB ${ALLEGRO_LIB}
)
target_link_libraries(MyLib PRIVATE Allegro)
file(GLOB ALLEGRO_DLL "${PROJECT_SOURCE_DIR}/packages/allegro5/windows/x86/bin/*.dll")
foreach(dll ${ALLEGRO_DLL})
add_custom_command(TARGET MyLib POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${dll} $<TARGET_FILE_DIR:MyLib>)
endforeach()
endif()
Now in my, top level CMakeLists.txt is:
cmake_minimum_required(VERSION 3.15)
project(MyProject)
enable_testing()
add_subdirectory(core)
add_executable(MyGame main.cpp)
target_link_libraries(MyGame MyLib)
In my IDE (Visual Studio) I see that the include statement for "allegro5/allegro.h" in my source files is inside core folder is giving me the warning "Cannot find directory allegro5 in search paths ... in context of ../src/main.cpp".
When I build the project I get the errors:
Cannot open source file 'allegro5/allegro'
Cannot open include file 'allegro5/allegro.h': No such file or directory.
This error only happens if I reference MyLib in main.cpp. (My main does not have any code, just a hello world statement):
// #include "MyLib.hpp"
int main(int argc, const char *argv[])
{
/*const auto engine = &MyLib::EngineManager::getInstance();
engine->start();
const auto display = &MyLib::DisplayManager::getInstance();
auto displayConfig = DisplayConfig();
displayConfig.fullscreen = false;
const auto displayId = display->createDisplay(displayConfig);*/
}
I guess this has something to do with the visibility I'm setting somewhere? I can't quite figure out how to fix. Appreciate your help, thanks!
EDIT:
When PRIVATE to PUBLIC, I get the following linker error:
LNK2019 unresolved external symbol __imp_al_install_system referenced in function "public: static void __cdecl mylib::EngineManager::start(void)" (?start#EngineManager#mylib##SAXXZ) C:\Users\xxx\src\out\build\x64-Debug\src C:\Users\xxx\src\out\build\x64-Debug\main.cpp.obj
The include directory for allegro5 is defined as ALLEGRO_DIR in your CMake:
${PROJECT_SOURCE_DIR}/packages/allegro5/include
Therefore, with the #include "allegro5/allegro.h", the full path to the header file would be appended:
${PROJECT_SOURCE_DIR}/packages/allegro5/include/allegro5/allegro.h
Be sure this path is correct and the file exists.
In addition, you set the INTERFACE include directories on the imported Allegro target, but you link it to MyLib using the PRIVATE keyword. This means the usage requirements of Allegro are not propagated to the MyGame. You should use PUBLIC for this link step instead if you want the INTERFACE_INCLUDE_DIRECTORIES of Allegro to also be transitively propagated to MyGame:
target_link_libraries(MyLib PUBLIC Allegro)
CMake has a good example demonstrating this in their documentation.

Trying to add libraries with CMake results in error

I am trying to add an external .lib file to my project in Clion which uses CMake. My code is very simple and is simply to test whether the library gets included:
#include <iostream>
#include "header/test.h"
int main() {
test a; // returns error saying undefined reference to 'test::test()'
return 0;
}
When running this code I get the following error:
undefined reference to `test::test()'
This is because I am trying to make a test object however the library for test is not included.
The test.lib file and the test.h file are both in the "header" folder which is in the root of my project folder. The file path to this is F:\Project\header\
My Cmake text file is as follows:
cmake_minimum_required(VERSION 3.14)
project(Project)
set(CMAKE_CXX_STANDARD 14)
add_executable(Project main.cpp)
target_link_libraries(Project
F:\\Project\\header\\test.lib)
In the cmake text file i use the line:
target_link_libraries(Project F:\Project\header\test.lib)
This should include the library file, however it doesn't seem to because I get the "undefined reference to..." error as mentioned above. The Cmake compiler does not give me an error.
You are conceptually correct, however you are not doing it in the CMake fashion. Check out the following links on how to link an external library.
CMake link to external library
cmake doesn't support imported libraries?
https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/Exporting-and-Importing-Targets
For your case, it would be as follows):
cmake_minimum_required(VERSION 3.14)
project(Project)
set(CMAKE_CXX_STANDARD 14)
# Import the library into the CMake build system
ADD_LIBRARY(test SHARED IMPORTED)
# Specify the location of the library
SET_TARGET_PROPERTIES(TARGET test PROPERTIES IMPORTED_LOCATION “/path/to/lib/test.dll”)
# create the executable
add_executable(Project main.cpp)
# Link your exe to the library
target_link_libraries(Project test)
The CMake documentation is very good. I recommend checking it out when you run into issues.
https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries

Why does Clion not detect standard library headers when using Cmake?

I have a project in Clion using CMake and C++14. The project compiles but all standard library includes are marked as:
"Cannot find string", "Cannot find stdexcept", etc.
Additionally the symbols from the dll I included are not being detected. So they are all marked as:
"Cannot resolve ..."
I've included the header and cmakelist.txt. This is only happening in this project and I have almost identical cmakelist.txt files for all my projects. I have tried restarting CLion's cache. I also tried moving all the files to a new project which worked momentarily but with an hour CLion was flagging these lines again.
cmakelists.txt
cmake_minimum_required(VERSION 3.6)
project(BCI)
set(CMAKE_CXX_STANDARD 14)
#create dlls and executables in the root directory
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
include_directories(
${CMAKE_SOURCE_DIR}
)
set(SOURCE_FILES
NeuralInterface.hpp
)
add_library(BCI SHARED ${SOURCE_FILES})
set_target_properties(BCI PROPERTIES LINKER_LANGUAGE CXX)
NeuralInterface.hpp
#ifndef NEURALINTERFACE_HPP
#define NEURALINTERFACE_HPP
//c++ includes
#include <stdexcept> //these are the includes which cannnot be resolved
#include <string>
//project includes
#include "okFrontPanelDLL.h"
extern std::string IntanAcquire; //this says cannot resolve container std
...
#endif
What else can I do to CMake so it finds these headers?