mgerhardy / caveexpress

CaveExpress is a classic 2D platformer with physics-based gameplay and dozens of levels. CavePacker is a Sokoban game.
http://www.caveproductions.org/
Other
144 stars 20 forks source link

CMAKE: Underlinking issues [-Wl,--as-needed] #96

Closed akien-mga closed 8 years ago

akien-mga commented 8 years ago

I'm working on packaging caveexpress for Mageia (with some inspiration from Markus Koschany who just got it packaged in Debian). Our default %cmake macro enforces these flags:

  CFLAGS="${CFLAGS:--O2 -g -pipe -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4}" ; export CFLAGS ; 
  CXXFLAGS="${CXXFLAGS:--O2 -g -pipe -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4}" ; export CXXFLAGS ; 
  FFLAGS="${FFLAGS:--O2 -g -pipe -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4}" ; export FFLAGS ; 
  LDFLAGS="${LDFLAGS:- -Wl,--as-needed -Wl,--no-undefined -Wl,-z,relro -Wl,-O1 -Wl,--build-id -Wl,--enable-new-dtags}" ; export LDFLAGS 

The -Wl,--as-needed ldflag is notorious for finding underlinking issues, which it did (supposedly, haven't investigated much yet) in the current HEAD:

[ 38%] Linking CXX shared library ../../../RelWithDebInfo/lib/libcavepacker-shared.so
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o: In function `cavepacker::CavePackerSQLitePersister::CavePackerSQLitePersister(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/cavepacker/shared/CavePackerSQLitePersister.cpp:6: undefined reference to `SQLitePersister::SQLitePersister(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o: In function `cavepacker::CavePackerSQLitePersister::~CavePackerSQLitePersister()':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/cavepacker/shared/CavePackerSQLitePersister.cpp:17: undefined reference to `SQLitePersister::~SQLitePersister()'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x20): undefined reference to `SQLitePersister::saveCampaign(Campaign*)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x28): undefined reference to `SQLitePersister::loadCampaign(Campaign*)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x30): undefined reference to `SQLitePersister::reset()'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x38): undefined reference to `SQLitePersister::resetCampaign(Campaign*)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x40): undefined reference to `SQLitePersister::init()'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x50): undefined reference to `SQLitePersister::deleteMaps(Campaign*)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x58): undefined reference to `SQLitePersister::activateCampaign(Campaign const*)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x60): undefined reference to `SQLitePersister::activateCampaign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x68): undefined reference to `SQLitePersister::saveLives(unsigned char, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x70): undefined reference to `SQLitePersister::loadCampaignMapParameters(CampaignMap*, SQLiteStatement&)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x78): undefined reference to `SQLitePersister::saveCampaignMapParameters(CampaignMap const*, SQLiteStatement&)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x80): undefined reference to `SQLitePersister::loadActiveCampaign[abi:cxx11]()'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x88): undefined reference to `SQLitePersister::updateCampaign(Campaign*)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x90): undefined reference to `SQLitePersister::resetState(Campaign*)'
CMakeFiles/cavepacker-shared.dir/CavePackerSQLitePersister.cpp.o:(.data.rel.ro._ZTVN10cavepacker25CavePackerSQLitePersisterE[_ZTVN10cavepacker25CavePackerSQLitePersisterE]+0x98): undefined reference to `SQLitePersister::loadLives(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
collect2: error: ld returned 1 exit status
src/cavepacker/shared/CMakeFiles/cavepacker-shared.dir/build.make:462: recipe for target 'RelWithDebInfo/lib/libcavepacker-shared.so' failed
[ 58%] Linking CXX shared library ../../../RelWithDebInfo/lib/libui.so
CMakeFiles/ui.dir/nodes/UINodeMapControl.cpp.o: In function `UINodeMapControl::isActive() const':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/UINodeMapControl.cpp:31: undefined reference to `ClientMap::isStarted() const'
CMakeFiles/ui.dir/nodes/UINodeMapControl.cpp.o: In function `UINodeMapControl::removeFocus(UIFocusRemovalReason)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/UINodeMapControl.cpp:41: undefined reference to `ClientMap::resetAcceleration(unsigned char, unsigned char) const'
CMakeFiles/ui.dir/nodes/UINodeMapControl.cpp.o: In function `UINodeMapControl::update(unsigned int)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/UINodeMapControl.cpp:68: undefined reference to `ClientMap::accelerate(unsigned char, unsigned char) const'
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/UINodeMapControl.cpp:75: undefined reference to `ClientMap::resetAcceleration(unsigned char, unsigned char) const'
CMakeFiles/ui.dir/nodes/UINodeMapFingerControl.cpp.o: In function `UINodeMapFingerControl::isActive() const':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/UINodeMapFingerControl.cpp:54: undefined reference to `ClientMap::isStarted() const'
CMakeFiles/ui.dir/nodes/UINodeMapFingerControl.cpp.o: In function `UINodeMapFingerControl::update(unsigned int)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/UINodeMapFingerControl.cpp:46: undefined reference to `ClientMap::setFingerAcceleration(int, int) const'
CMakeFiles/ui.dir/nodes/UINodeMapFingerControl.cpp.o: In function `UINodeMapFingerControl::onFingerRelease(long, unsigned short, unsigned short, bool)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/UINodeMapFingerControl.cpp:85: undefined reference to `ClientMap::stopFingerAcceleration() const'
CMakeFiles/ui.dir/nodes/UINodeMapFingerControl.cpp.o: In function `UINodeMapFingerControl::removeFocus(UIFocusRemovalReason)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/UINodeMapFingerControl.cpp:25: undefined reference to `ClientMap::stopFingerAcceleration() const'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `ClientMap::setSize(int, int)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/ClientMap.h:302: undefined reference to `Camera::init(int, int, int, int, int)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `IUINodeMap::render(int, int) const':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/IUINodeMap.cpp:175: undefined reference to `ClientMap::isStarted() const'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `IUINodeMap::onPop()':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/IUINodeMap.cpp:199: undefined reference to `ClientMap::close()'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `IUINodeMap::move(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, unsigned char)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/IUINodeMap.cpp:104: undefined reference to `ClientMap::resetAcceleration(unsigned char, unsigned char) const'
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/IUINodeMap.cpp:111: undefined reference to `ClientMap::accelerate(unsigned char, unsigned char) const'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `RumbleHandler::execute(RumbleMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/RumbleHandler.h:21: undefined reference to `ClientMap::rumble(float, int)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `RemoveEntityHandler::execute(RemoveEntityMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/RemoveEntityHandler.h:20: undefined reference to `ClientMap::removeEntity(unsigned short, bool)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `UpdateEntityHandler::execute(UpdateEntityMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/UpdateEntityHandler.h:18: undefined reference to `ClientMap::updateEntity(unsigned short, float, float, short, unsigned char)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `ChangeAnimationHandler::execute(ChangeAnimationMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/ChangeAnimationHandler.h:20: undefined reference to `ClientMap::changeAnimation(unsigned short, Animation const&)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `RumbleHandler::execute(RumbleMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/RumbleHandler.h:21: undefined reference to `ClientMap::rumble(float, int)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `RemoveEntityHandler::execute(RemoveEntityMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/RemoveEntityHandler.h:20: undefined reference to `ClientMap::removeEntity(unsigned short, bool)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `ChangeAnimationHandler::execute(ChangeAnimationMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/ChangeAnimationHandler.h:20: undefined reference to `ClientMap::changeAnimation(unsigned short, Animation const&)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `UpdateEntityHandler::execute(UpdateEntityMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/UpdateEntityHandler.h:18: undefined reference to `ClientMap::updateEntity(unsigned short, float, float, short, unsigned char)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `LoadMapHandler::execute(LoadMapMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/LoadMapHandler.h:33: undefined reference to `ClientMap::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/LoadMapHandler.h:33: undefined reference to `ClientMap::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `CloseMapHandler::execute(CloseMapMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/CloseMapHandler.h:40: undefined reference to `ClientMap::close()'
CMakeFiles/ui.dir/nodes/IUINodeMap.cpp.o: In function `FinishedMapHandler::execute(FinishedMapMessage const*)':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/FinishedMapHandler.h:49: undefined reference to `ClientMap::close()'
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/client/network/FinishedMapHandler.h:49: undefined reference to `ClientMap::close()'
CMakeFiles/ui.dir/windows/IUIMapWindow.cpp.o: In function `IUINodeMap::initWaitingForPlayer()':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/nodes/IUINodeMap.h:74: undefined reference to `ClientMap::initWaitingForPlayer()'
CMakeFiles/ui.dir/windows/IUIMapWindow.cpp.o: In function `IUIMapWindow::onActive()':
/home/akien/Mageia/Sandbox/caveexpress/BUILD/caveexpress-2.4+20160614/src/modules/ui/windows/IUIMapWindow.cpp:143: undefined reference to `ClientMap::isStarted() const'
collect2: error: ld returned 1 exit status
src/modules/ui/CMakeFiles/ui.dir/build.make:1378: recipe for target 'RelWithDebInfo/lib/libui.so' failed

System: Mageia 6 x86_64, GCC 5.4.0.

mgerhardy commented 8 years ago

I'm a little bit confused, because I use static libs to link the binary. I've just split up the codebase into modules but still only have one binary, no shared libs. diff --git a/cmake/toolchains/linux-toolchain.cmake b/cmake/toolchains/linux-toolchain.cmake index 71f16a0..a15c1f1 100644 --- a/cmake/toolchains/linux-toolchain.cmake +++ b/cmake/toolchains/linux-toolchain.cmake @@ -62,3 +62,4 @@ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG -fno-omit-frame-pointer set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -Wnon-virtual-dtor") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed -Wl,--no-undefined -Wl,-z,relro -Wl,-O1 -Wl,--build-id -W")

Applying this patch also didn't reveal any problems

akien-mga commented 8 years ago

Hm, I guess the issue appears only when using -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=OFF, which is default in Mageia's %cmake macro.

I'll investigate a bit more asap. I agree that building the modules as shared libs is not particularly meaningful here though, so I'll probably disable our default -DBUILD_SHARED_LIBS=ON to package caveexpress.

mgerhardy commented 8 years ago

Can this be closed? Or do you still have any issues with it?

akien-mga commented 8 years ago

I still need to give it a try, thanks for the reminder. I think that the proper fix here though would be to force static linking instead of honouring the BUILD_SHARED_LIBS argument.

It could likely be done by adding the STATIC flag to the add_library calls, or by enforcing that BUILD_SHARED_LIBS is set to OFF and BUILD_STATIC_LIBS is set to ON (with a message(STATUS ...) telling the user that their instruction was overridden).