[CMake] Correct way to link with libstdc++ from non-C++ project?

Michael Hertling mhertling at online.de
Fri Sep 16 18:10:55 EDT 2011


On 09/15/2011 06:39 PM, Jed Brown wrote:
> Suppose project Foo depends on a library Bar that uses C++ internally, but
> was not properly linked, so foo would need to be linked with
> 
> 1. $CC -shared -o libfoo.so *.o -lbar -lstdc++
> 
> or
> 
> 2. $CXX -shared -o libfoo.so *.o -lbar
> 
> 
> Note that
> 
> find_library (LIBSTDCXX NAMES stdc++)
> 
> does not work because this library is often not in a public directory, so a
> full path cannot be resolved. My understanding is that current recommended
> practice is to use option 2 above, but this breaks down if Foo also needs to
> link some Fortran libraries because you can't link using both the C++
> compiler and the Fortran compiler.
> 
> If the Fortran and C++ compilers come from the same suite, passing a literal
> "-lstdc++" will generally work, but this is not robust if they come from
> different suites. Is there a way to mark a library as depending on a
> language or some other internal compiler library, so that CMake will sort
> out how to do the multi-language link in the same way it does if the project
> has source files in each language?

Supposedly, your library Bar is not part of your CMake-built project
Foo; otherwise, it would be perfectly linked, wouldn't it? ;-) In your
case, you might apply the following trick: Provide an empty static C++
helper library, import the badly linked Bar library and make it depend
on the helper. In this way, the helper appears after Bar in the linker
command line, and since CMake recognizes the helper as a C++ library,
the libstdc++ is additionally pulled in after the helper. Look here:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(HELPER C CXX)
SET(CMAKE_VERBOSE_MAKEFILE ON)
# Create empty static C++ helper library:
FILE(WRITE ${CMAKE_BINARY_DIR}/helper.cxx "")
ADD_LIBRARY(helper STATIC helper.cxx)
# Create badly linked bar library:
FILE(WRITE ${CMAKE_BINARY_DIR}/bar.cxx
"#include <iostream>
extern \"C\" void bar(void){std::cout<<\"FooBar!\\n\";}\n")
EXECUTE_PROCESS(COMMAND g++ -c bar.cxx)
EXECUTE_PROCESS(COMMAND g++ -shared -nodefaultlibs -o libbar.so bar.o)
# Import it and make it depend on helper:
ADD_LIBRARY(bar SHARED IMPORTED)
SET_TARGET_PROPERTIES(bar PROPERTIES
    IMPORTED_LOCATION libbar.so
    IMPORTED_LINK_INTERFACE_LIBRARIES helper
)
ADD_DEPENDENCIES(bar helper)
# Create C target foo depending on bar:
FILE(WRITE ${CMAKE_BINARY_DIR}/foo.c
"int main(void){bar(); return 0;}\n")
ADD_EXECUTABLE(foo foo.c)
TARGET_LINK_LIBRARIES(foo bar)
SET_TARGET_PROPERTIES(foo PROPERTIES LINKER_LANGUAGE C)

Due to CMAKE_CXX_LINKER_PREFERENCE > CMAKE_C_LINKER_PREFERENCE and
CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES == TRUE, the target foo must
be marked explicitly as to be linked via C. In the end, the library
bar contains C++ code usable from C but is linked without the usual
dependency on libstdc++. The final target foo is linked against bar
and refers to the latter's code while the libstdc++ along with its
dependencies appears in the linker command line, too, although foo
is linked via the C compiler, not the C++ one. Linking against the
empty static helper library doesn't mean any harm. If I'm not mis-
taken, that's what you intend, albeit I don't know whether this
approach can be denoted as "correct"...

Anyway, 'hope that helps.

Regards,

Michael


More information about the CMake mailing list