I'm building with g++/KDevelop/CMake(3.16.3).
Before I put cmake_minimum_required( VERSION 3.0.0 )
in the first line of my CMakeLists.txt and everythings OK, now I need change it to cmake_minimum_required( VERSION 3.4.0 )
because of other requirements.But with this I can NOT load the libs with new main program.
My programs are some little *.so libs as "Module", and be dlopen
by the main program.
header.hpp
#pragma once
int GetNumber();
littleModule.cpp
#include "header.hpp"
extern "C" int newStrategy() {
return GetNumber();
};
loader.cpp
#include <dlfcn.h>
#include "header.hpp"
int GetNumber() {
return 123;
};
bool anyError( void* pFunc ) {
const char* err_msg = dlerror();
if( err_msg != nullptr ) {
lg_erro << "Error on loading:" << err_msg;
return true;
}
if( pFunc == nullptr ) {
lg_erro << "Error on loading:NULL ptr";
return true;
}
return false;
};
using StrategyMaker_f = auto( * )()->int;
int main( int argc, char** args ) {
void* pFunc = args; // any ptr not NULL
// no err left before
if( anyError( pFunc ) )
exit( EXIT_FAILURE );
auto lib_handle = dlopen( "/path/to/modules/littleModule.so", RTLD_NOW );
if( anyError( lib_handle ) )
exit( EXIT_FAILURE );
pFunc = dlsym( lib_handle, "newStrategy" );
if( anyError( pFunc ) )
exit( EXIT_FAILURE );
auto _mk_func = reinterpret_cast<StrategyMaker_f>( pFunc );
lg_debg << "Success with:" << _mk_func();
exit( EXIT_SUCCESS );
};
CMakeLists.txt (loader.cpp)
cmake_minimum_required( VERSION 3.0.0 )
# cmake_minimum_required( VERSION 3.4.0 )
add_executable( loader Loader.cpp
common/log/Log2Console.cpp
common/misc/Converts.cpp
)
target_link_libraries( loader dl )
install( TARGETS loader RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
CMakeLists.txt (littleModule.cpp)
cmake_minimum_required( VERSION 3.0.0 )
# cmake_minimum_required( VERSION 3.4.0 ) still don't work
# add_library( littleModule SHARED littleModule.cpp )
# As @Tsyvarev's hint
add_library( littleModule MODULE littleModule.cpp )
set_target_properties( littleModule PROPERTIES
PREFIX ""
OUTPUT_NAME_RELEASE littleModule
OUTPUT_NAME_DEBUG littleModule
VERSION ${PROJECT_VERSION}
)
install( TARGETS littleModule LIBRARY DESTINATION strategies )
Error Output:
Error on loading:undefined symbol: _Z9GetNumberv
This is caused by policy CMP0065 which states:
New in version 3.4.
Do not add flags to export symbols from executables without the
ENABLE_EXPORTS
target property.CMake 3.3 and below, for historical reasons, always linked executables on some platforms with flags like
-rdynamic
to export symbols from the executables for use by any plugins they may load viadlopen
. CMake 3.4 and above prefer to do this only for executables that are explicitly marked with theENABLE_EXPORTS
target property.The
OLD
behavior of this policy is to always use the additional link flags when linking executables regardless of the value of theENABLE_EXPORTS
target property.The
NEW
behavior of this policy is to only use the additional link flags when linking executables if theENABLE_EXPORTS
target property is set toTrue
.This policy was introduced in CMake version 3.4. Unlike most policies, CMake version 3.24.0-rc2 does not warn by default when this policy is not set and simply uses
OLD
behavior. See documentation of theCMAKE_POLICY_WARNING_CMP0065
variable to control the warning.Note: The
OLD
behavior of a policy is deprecated by definition and may be removed in a future version of CMake.
Hence, CMake is working as intended. Indeed this is a reasonable policy; adding such flags affects how the linker loads libraries and can have performance consequences when such functionality isn't actually used.
To fix your program, write:
add_executable(loader
Loader.cpp
common/log/Log2Console.cpp
common/misc/Converts.cpp
)
target_link_libraries(loader PRIVATE ${CMAKE_DL_LIBS})
set_target_properties(loader PROPERTIES ENABLE_EXPORTS TRUE)
The last line is the important one for your problem; it will make sure that symbols in your executable are available to dynamically loaded libraries/plugins. The change from dl
to ${CMAKE_DL_LIBS}
is to account for systems which don't have a separate dl
lib or have it named differently (for instance most BSDs including macOS, and HP-UX).