compiler options after LINK_FLAGS and

I am sure I did something stupid but one of these things also appears to be platform specific. I don’t generally create cmake scripts for shared libraries from scratch, but am trying for a new project now.

Created an empty class to build into the Core library (multiple libraries naturally) to get the plumbing to work for generating the library and its Debian package. First make certain the toilet flushes, then . . .

On Ubuntu 24.04 with all updates applied and MX Linux with all updates applied the build dies in mostly the same way.

[1/4] Building CXX object src/core/CMakeFiles/BD_Core.dir/bd_object.cpp.o
FAILED: src/core/CMakeFiles/BD_Core.dir/bd_object.cpp.o 
/usr/bin/c++ @src/core/CMakeFiles/BD_Core.dir/bd_object.cpp.o.rsp -MD -MT src/core/CMakeFiles/BD_Core.dir/bd_object.cpp.o -MF src/core/CMakeFiles/BD_Core.dir/bd_object.cpp.o.d -o src/core/CMakeFiles/BD_Core.dir/bd_object.cpp.o -c /home/developer/sf_projects/basisdoctrina/src/core/bd_object.cpp
c++: warning: LINK_FLAGS: linker input file unused because linking not done
c++: error: LINK_FLAGS: linker input file not found: No such file or directory
ninja: build stopped: subcommand failed.

The beautified .rsp for Ubuntu has

cat ../basisdoctrina_debian_build/src/core/CMakeFiles/BD_Core.dir/bd_object.cpp.o.rsp
-DBD_Core_EXPORTS 
-DBD_PACKAGE_BUILD 
-DBD_SHARED 
-I/home/developer/sf_projects/basisdoctrina_debian_build/src/core 
-I/home/developer/sf_projects/basisdoctrina/src/core 
-I/usr/lib/x86_64-linux-gnu/glib-2.0/include 
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/sigc++-2.0/include 
-I/usr/include/sigc++-2.0 
-I/usr/lib/x86_64-linux-gnu/glibmm-2.4/include 
-I/usr/include/glibmm-2.4 
-I/home/developer/sf_projects/basisdoctrina/src/core/include/core 
-I/home/developer/sf_projects/basisdoctrina_debian_build/include -g -std=c++17 -fPIC LINK_FLAGS

Please note the difference at the end for MX Linux

$ cat ../basisdoctrina_debian_build/src/core/CMakeFiles/BD_Core.dir/bd_object.cpp.o.rsp
-DBD_Core_EXPORTS 
-DBD_PACKAGE_BUILD 
-DBD_SHARED 
-I/home/developer/sf_projects/basisdoctrina_debian_build/src/core 
-I/home/developer/sf_projects/basisdoctrina/src/core 
-I/usr/lib/x86_64-linux-gnu/glib-2.0/include 
-I/usr/include/glib-2.0 
-I/usr/lib/x86_64-linux-gnu/sigc++-2.0/include 
-I/usr/include/sigc++-2.0 
-I/usr/lib/x86_64-linux-gnu/glibmm-2.4/include 
-I/usr/include/glibmm-2.4 
-I/home/developer/sf_projects/basisdoctrina/src/core/include/core 
-I/home/developer/sf_projects/basisdoctrina_debian_build/include -g -fPIC LINK_FLAGS -std=c++17

That had me chasing a Red Herring that was swimming down a rabbit hole for over a day.

Only interesting part of the CMakeLists.txt from the project src dir is as follows

include(CPack)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)

if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
   set(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS}    -Wl,-undefined,error")
   set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-undefined,error")
   set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-undefined,error")

elseif (CMAKE_SYSTEM_NAME MATCHES "(OpenBSD|FreeBSD|NetBSD|DragonFly)")
   set(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS}    -Wl,--no-undefined")
   set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ")
   set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined")

elseif (MSVC)
   string (REGEX REPLACE "/W3" "" CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}"  )
   string (REGEX REPLACE "/W3" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    
   add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/utf-8>")

else()
   # Linux, Windows (MinGW)

   set(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS}    -Wl,--no-undefined")
   set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
   set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined")

   if (CMAKE_SYSTEM_NAME MATCHES "Windows")
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
      set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -Wa,-mbig-obj")
   endif()

endif()

It’s not all that interesting. Rewrote this CMakeLists.txt that is in the core subdirectory of source many times. Obviously missing something the documentation simply hasn’t been able to explain to me.

list(APPEND CORE_INCLUDES
  ${CMAKE_BINARY_DIR}/include/bd_build_info.h
  ${CMAKE_SOURCE_DIR}/src/core/bd_object.h
  ${CMAKE_SOURCE_DIR}/src/3rdparty/BigInt/BigInt.hpp
)

list(APPEND CORE_SOURCES
  ${CMAKE_SOURCE_DIR}/src/core/bd_object.cpp
)

add_library(BD_Core SHARED ${CORE_SOURCES})
add_library(Bd::BD_Core ALIAS BD_Core)


set_target_properties(BD_Core PROPERTIES
  VERSION ${BUILD_ABI}
  SOVERSION ${BUILD_MAJOR}
  OUTPUT_NAME BD_Core${BUILD_ABI}
)


target_include_directories(BD_Core
   PRIVATE
   $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/core>
   $<INSTALL_INTERFACE:include/core>
   ${CMAKE_BINARY_DIR}/include
   ${ZLIB_INCLUDE_DIR}
   ${SDL3_INCLUDE_DIR}
)


# Raspberry Pi does not have built in atomic support
if (HAVE_LIBATOMIC)
   target_link_libraries(BD_Core
      PUBLIC
      atomic
   )
endif()

function_clean_string("${EXTRA_CORE_CXXFLAGS}" EXTRA_CORE_CXXFLAGS)
function_clean_string("${EXTRA_CORE_LDFLAGS}"  EXTRA_CORE_LDFLAGS)

target_sources(BD_Core
  PRIVATE
  ${CORE_INCLUDES}
  ${CORE_SOURCES}
)

set_target_properties(BD_Core
   PROPERTIES
   COMPILE_FLAGS ${EXTRA_CORE_CXXFLAGS}
   LINK_FLAGS    ${EXTRA_CORE_LDFLAGS}
   CXX_STANDARD 17
   CSS_STANDARD_REQUIRED ON
   CXX_EXTENSIONS OFF
)

target_link_libraries(BD_Core
   PRIVATE
   ${ZLIB_LIBRARIES}
   ${SDL3_LIBRARIES}
)

if(MSVC)
   target_compile_options(BD_Core
      PUBLIC
      /bigobj
      /DNOMINMAX
   )

   if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0")
      # ensure method pointers have a unique address
      target_link_options(BD_Core
         PUBLIC
         /OPT:REF,NOICF
      )
   else()
      message(FATAL_ERROR "CMake Version must be at least 3.13.0 for MSVC")

   endif()
endif()


#
# If we get around to adding translations we will need to do something with
# the translation files at this time.
#
# Hopefully we will come up with something better than .qrc and rcc
#

get_target_property(OUT BD_Core LINK_LIBRARIES)

message("   ***   ")
message("   ***   ")
message("   ***   ")

message("\tlibraries: ${OUT}")
message("\tEXTRA_CORE_LDFLAGS:  ${EXTRA_CORE_LDFLAGS}")
message("\tEXTRA_CORE_CXXFLAGS: ${EXTRA_CORE_CXXFLAGS}")
message("\tZLIB_LIBRARIES:      ${ZLIB_LIBRARIES}")
message("\tSDL3_LIBRARIES:      ${SDL3_LIBRARIES}")
message("\tCMAKE_CXX_FLAGS:     ${CMAKE_CXX_FLAGS}")
message("\tCMAKE_C_FLAGS:       ${CMAKE_C_FLAGS}")
message("\tCMAKE_SHARED_LINKER_FLAGS:  ${CMAKE_SHARED_LINKER_FLAGS}")
message("\tCMAKE_EXE_LINKER_FLAGS:     ${CMAKE_EXE_LINKER_FLAGS}")
message("   ***   ")
message("   ***   ")
message("   ***   ")

if (UNIX)
    set(P_NAME "BD_Core")
    set(P_INC_SUBDIR "Core")
    set(P_CFLAGS "${EXTRA_CORE_CXXFLAGS}")
    set(P_REQUIRES "")

    configure_file(
        ${CMAKE_SOURCE_DIR}/cmake/pkgconfig.cmake
        ${CMAKE_BINARY_DIR}/pkgconfig/${P_NAME}.pc
        @ONLY
    )

    install(
        FILES ${CMAKE_BINARY_DIR}/pkgconfig/${P_NAME}.pc
        DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig
        COMPONENT Devel
    )
endif()

  
# multi-arch Debian has an extra director after /lib
# for 64-bit x86 is is x86_64-linux-gnu
# various ARM platforms will have other directories.
#
if (DEBIAN_FOUND)
    install(
        TARGETS BD_Core
        EXPORT BdLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}
        LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    )
else()
    install(
        TARGETS BD_Core
        EXPORT BdLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
endif()


install(FILES ${CMAKE_BINARY_DIR}/include/bd_config.h  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} )

Please note the big block of cmake debugger statements. They generate the following

   ***   
   ***   
   ***   
	libraries: /usr/lib/x86_64-linux-gnu/libz.so;SDL3::SDL3
	EXTRA_CORE_LDFLAGS:  
	EXTRA_CORE_CXXFLAGS: 
	ZLIB_LIBRARIES:      /usr/lib/x86_64-linux-gnu/libz.so
	SDL3_LIBRARIES:      SDL3::SDL3
	CMAKE_CXX_FLAGS:     
	CMAKE_C_FLAGS:       
	CMAKE_SHARED_LINKER_FLAGS:   -Wl,--no-undefined
	CMAKE_EXE_LINKER_FLAGS:         -Wl,--no-undefined
   ***   
   ***   
   ***

So, I have it declared as a shared library. There is exactly one module in it that does nothing. The target link libraries are correct for what this particular library will need . . . but . . .doesn’t create the library so the shell script can go on and create the Debian package.

What am I missing?

For anyone that wants the entire thing, you can clone it from here

debian-build-dependencies.sh will install everything needed, even build the SDL3 library from source and install

build-BasisDoctrina-deb.sh will kick of the build

The word LINK_FLAGS has been added to your compiler flags. That is simply wrong.

I guess the variable EXTRA_CORE_CXXFLAGS is empty in this part:

set_target_properties(BD_Core
   PROPERTIES
   COMPILE_FLAGS ${EXTRA_CORE_CXXFLAGS}
   LINK_FLAGS    ${EXTRA_CORE_LDFLAGS}
   CXX_STANDARD 17
   CSS_STANDARD_REQUIRED ON
   CXX_EXTENSIONS OFF
)

which most likely causes it to be misinterpreted.

Instead of setting such properties manually I suggest to you the appropriate target_* commands.

1 Like

Thank you for your feedback.

That was one of the seemingly 200+ iterations I tried. No matter what LINK_FLAGS gets put into that response file. Yes, the variables you asked about are empty, here is the cmake debugger output again.




libraries: /usr/lib/x86_64-linux-gnu/libz.so;SDL3::SDL3
EXTRA_CORE_LDFLAGS:  
EXTRA_CORE_CXXFLAGS: 
ZLIB_LIBRARIES:      /usr/lib/x86_64-linux-gnu/libz.so
SDL3_LIBRARIES:      SDL3::SDL3
CMAKE_CXX_FLAGS:     
CMAKE_C_FLAGS:       
CMAKE_SHARED_LINKER_FLAGS:   -Wl,--no-undefined
CMAKE_EXE_LINKER_FLAGS:         -Wl,--no-undefined



I deleted the COMPILE_FLAGS and LINK_FLAGS lines since those were both empty variables.
Indeed, all the way back to Ubuntu 20.04, cmake has no idea what to do if you set those (possibly other) target properties to empty strings.

Thank you.

When the variables are empty, it’s as if they are not there in the first place.
So you did set the property COMPILE_FLAGS to the value LINK_FLAGS.

So the safe way to do this command would have been to add quotes around the variables:

set_target_properties(BD_Core
   PROPERTIES
   COMPILE_FLAGS "${EXTRA_CORE_CXXFLAGS}"
   LINK_FLAGS    "${EXTRA_CORE_LDFLAGS}"
   CXX_STANDARD 17
   CSS_STANDARD_REQUIRED ON
   CXX_EXTENSIONS OFF
)

In that case, each value property is an empty string, if the variable is empty.

In case of a list of flags, it would have been even worse without the quotation marks. The Flags would have been interpreted as property names and values.

I suggest to do it like this:

target_compile_options(BD_Core
  PRIVATE
    ${EXTRA_CORE_CXXFLAGS}
)

Here it’s important to not add quotation marks.
Because you want all list elements interpreted as a separate flag.

1 Like