conan: Symbols not found when linking against library provided by conan

To help us debug your issue please explain:

  • I’ve read the CONTRIBUTING guide.
  • I’ve specified the Conan version, operating system version and any tool that can be relevant.
  • I’ve explained the steps to reproduce the error or the motivation/use case of the question/suggestion.

I’m back with more questions. I apologize, as I cannot tell at all where the problem lies. In short, on Linux, using GCC (verified with gcc6, but I bet it exists with other versions, and maybe with clang too) (notably, this is a non-issue on OSX), if you take this sample code: https://github.com/DEGoodmanWilson/luna/tree/testing/5.0.0/examples/project_template (note I’m working in branch testing/5.0.0 and do a conan install . && cmake . && cmake --build ., you get the following linker errors:

main.cpp:(.text+0x188): undefined reference to `luna::set_error_logger(std::function<void (luna::log_level, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>)'
main.cpp:(.text+0x22b): undefined reference to `luna::server::create_router(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
main.cpp:(.text+0x2d6): undefined reference to `luna::router::handle_request(luna::request_method, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::function<luna::response (luna::request const&)>, std::vector<luna::parameter::validator, std::allocator<luna::parameter::validator> >)'
...and so on

OK, this looks like luna isn’t getting linked in. But, running cmake in verbose mode: cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON . I can see that the linker command line does include -lluna and the appropriate -L directives, and can verify that the paths provided with -L exist

Finally, a quick check of libluna.a reveals that these symbols are in fact getting exported: nm -g ~/.conan/data/luna/5.0.0/DEGoodmanWilson/testing/package/220f2ee147781d76ef20f65b797d3e21181cfd64/lib/libluna.a | c++filt | grep set_error_logger

00000000000001f0 T luna::set_error_logger(std::function<void (luna::log_level, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>)

The exported symbols don’t have the additional __cxx11 namespace qualifiers on std, which raises my suspicions a bit, but it’s clear we’re reaching the end of my experience here.

Is there something I’ve left out of the build process for luna that is causing this?

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 2
  • Comments: 37 (21 by maintainers)

Commits related to this issue

Most upvoted comments

Hi @DEGoodmanWilson

I’ve been reproducing your problem as you’ve explained at https://github.com/DEGoodmanWilson/luna/issues/49 with lasote/conangcc6

Your problem is related with How to manage the GCC >= 5 ABI.

You can see the following warning in conan when running for the first time in lasote/conangcc6:

conan@a023e116e7d1:/Users/pvicente/tmp/luna/examples/project_template$  conan install . && cmake . && cmake --build .
Auto detecting your dev setup to initialize the default profile (/home/conan/.conan/profiles/default)
Found gcc 6.4
gcc>=5, using the major as version

************************* WARNING: GCC OLD ABI COMPATIBILITY ***********************

Conan detected a GCC version > 5 but has adjusted the 'compiler.libcxx' setting to
'libstdc++' for backwards compatibility.
Your compiler is likely using the new CXX11 ABI by default (libstdc++11).

If you want Conan to use the new ABI, edit the default profile at:

    ~/.conan/profiles/default

adjusting 'compiler.libcxx=libstdc++11'

************************************************************************************



Default settings
	os=Linux
	os_build=Linux
	arch=x86_64
	arch_build=x86_64
	compiler=gcc
	compiler.version=6
	compiler.libcxx=libstdc++
	build_type=Release
*** You can change them in /home/conan/.conan/profiles/default ***
*** Or override with -s compiler='other' -s ...s***

In summary conan is using the old abi compatibility for libstdc++ to maintain backwards compatibility.

I can see that your project is using set(CMAKE_CXX_STANDARD 14).

You have two options to change this behaviour:

  • From command line: conan install . -s compiler.libcxx=libstdc++11 --build=missing && cmake . && cmake --build .
  • In default profile: conan profile update settings.compiler.libcxx=libstdc++11 default and then run conan install . --build=missing && cmake . && cmake --build .

Hope it helps to resolve your question. I’ve tried 1st option from the command line and it worked:

 conan install . -s compiler.libcxx=libstdc++11 --build=missing && cmake . && cmake --build .
...
/usr/bin/make -f tests/CMakeFiles/awesomesauce_tests.dir/build.make tests/CMakeFiles/awesomesauce_tests.dir/depend
make[2]: Entering directory '/Users/pvicente/tmp/luna/examples/project_template'
cd /Users/pvicente/tmp/luna/examples/project_template && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /Users/pvicente/tmp/luna/examples/project_template /Users/pvicente/tmp/luna/examples/project_template/tests /Users/pvicente/tmp/luna/examples/project_template /Users/pvicente/tmp/luna/examples/project_template/tests /Users/pvicente/tmp/luna/examples/project_template/tests/CMakeFiles/awesomesauce_tests.dir/DependInfo.cmake --color=
make[2]: Leaving directory '/Users/pvicente/tmp/luna/examples/project_template'
/usr/bin/make -f tests/CMakeFiles/awesomesauce_tests.dir/build.make tests/CMakeFiles/awesomesauce_tests.dir/build
make[2]: Entering directory '/Users/pvicente/tmp/luna/examples/project_template'
make[2]: Nothing to be done for 'tests/CMakeFiles/awesomesauce_tests.dir/build'.
make[2]: Leaving directory '/Users/pvicente/tmp/luna/examples/project_template'
[100%] Built target awesomesauce_tests
make[1]: Leaving directory '/Users/pvicente/tmp/luna/examples/project_template'
/usr/bin/cmake -E cmake_progress_start /Users/pvicente/tmp/luna/examples/project_template/CMakeFiles 0

BTW I’ve realised that lasote/conangcc6 doesn’t have pkg-config system package, which is neeeded to build conan-gnutls one of the project dependencies, so you’ll have to install it to do this test. I’ll open an issue to add it to all docker images.

Maybe it’s worth to rebuild in CI all of your dependency tree with both settings:

-compiler.libcxx=libstdc++ (default) for gcc<5
-compiler.libcxx=libstdc++11 for gcc>=5

This problem is not happening in MacOSX because it’s using clang and it uses libc++ which is fully compatible with C++11 and C++14 (in latest version).

See also some related issues:

@DEGoodmanWilson Yes, you can check about this on Conan package tools:

https://github.com/conan-io/conan-package-tools#complete-conanmultipackager-methods-reference

By default it uses pure_c=True that means, do not link libstc++11

They are actually different settings:

  • CMAKE_CXX_ variables set the C++ standard to build with C++14, 17, etc
  • CONAN_LIBCXX is intended to define which standard library you want to link with libstdc++11, libc++, etc. They are kind of unrelated, you can build your code with C++14 and don’t need to link with an hypothetical libstdc++14, but can link with libstdc++11. Compilers will have a default libcxx, modern gcc compilers in modern distros will link with libstdc++11, while old gcc compilers or new gcc compilers in old distros will still use libstdc++, and clang compilers might default to using libc++.

There might be different ways to define the libcxx natively in CMake, to be honest, I am not sure which one is really recommended, I tend to use set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")

Thanks to you for all the feedback!

clang decided to implement its own version of stdc++ library with libc++.

But you can use clang and link your program against the gcc version libstdc++.

If you run in lasote/conanclang40:

conan install . && cmake -DCONAN_LIBCXX=libstdc++ . && cmake --build .

it should work.

and to make it work with libc++ and clang:

conan install . -s compiler.libcxx=libc++ && cmake -DCONAN_LIBCXX=libc++ -DCONAN_COMPILER=clang . && cmake --build .

configure for this case.

The doc about these methods says config_options should only be used for options of the package and in this case we want to remove a setting (not an option) which is always set so it should be manipulated in config method.

See example about how to manipulate them (settings and options) in other recipe 😉

Hope it helps.

Hi @DEGoodmanWilson

I’ve checked the new problem and I can see that dependency libgpg-error was built with pure_c=True (default). This package is C_only package and the recipe should have a method:

    def configure(self):
        del self.settings.compiler.libcxx

It’s not well documented (I’ll fix it) but you can see some references about it in docs. Adding this method conan will ignore the libcxx setting for that library and it won’t generate any error when it’s consumed for any c++ package which is building with libcxx setting.

The best approach is to revisit all your dependencies a update the recipes for C-only packages/libraries.

With the latest conan version 1.1.1 if you run conan new for c package only:

$ conan new -c hello/0.1

You can see that the template conanfile has this method.

18:13 $ cat conanfile.py
from conans import ConanFile, CMake, tools


class HelloConan(ConanFile):
    name = "hello"
    version = "0.1"
    license = "<Put the package license here>"
    url = "<Package recipe repository url here, for issues about the package>"
    description = "<Description of Hello here>"
    settings = "os", "compiler", "build_type", "arch"
    options = {"shared": [True, False]}
    default_options = "shared=False"
    generators = "cmake"

    def source(self):
        self.run("git clone https://github.com/memsharded/hello.git")
        self.run("cd hello && git checkout static_shared")
        # This small hack might be useful to guarantee proper /MT /MD linkage in MSVC
        # if the packaged project doesn't have variables to set it properly
        tools.replace_in_file("hello/CMakeLists.txt", "PROJECT(MyHello)", '''PROJECT(MyHello)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()''')

    def build(self):
        cmake = CMake(self)
        cmake.configure(source_folder="hello")
        cmake.build()

        # Explicit way:
        # self.run('cmake %s/hello %s' % (self.source_folder, cmake.command_line))
        # self.run("cmake --build . %s" % cmake.build_config)

    def package(self):
        self.copy("*.h", dst="include", src="hello")
        self.copy("*hello.lib", dst="lib", keep_path=False)
        self.copy("*.dll", dst="bin", keep_path=False)
        self.copy("*.so", dst="lib", keep_path=False)
        self.copy("*.dylib", dst="lib", keep_path=False)
        self.copy("*.a", dst="lib", keep_path=False)

    def package_info(self):
        self.cpp_info.libs = ["hello"]

    def configure(self):
        del self.settings.compiler.libcxx

Hope it helps.

C libraries should not care about libcxx, Conan has no crystal ball to guess if the project is pure C, so you need to tell it:

class FoobarConan(Conanfile):
    ....
    def config_options(self):
        del self.settings.compiler.libcxx

After that, your package won’t care about libcxx in it package id. As result, Luna will works fine even liking libc++, libstdc++11 or libstdc++

Interestingly, I see that the option pure_c=False for add_common_builds() seems to add builds for both libstc++ and libstdc++11 already 😉

https://travis-ci.org/DEGoodmanWilson/base64/jobs/354380826