'Creating conan test_package recipe

I'm currently playing around with conan. So I've created two small project: The first project is a small library "fcdk": https://github.com/lmarzull/fcdk/tree/devel

The second is a project holding the conan and circle-ci stuff (don't know yet if I should group the library/conan/circle-ci in a single project, but this is not yet the point). The second project is called "fcdk-conan"

I decide to put the unit test of the library inside the fcdk-conan project in the "test_package" directory. I do so to avoid a dependencies on google test in my "fcdk" library and to rather have this dependency in the fcdk-conan project (don't know if it's a good idea)

I've create a very litte test program:

#include <iostream>

int
main()
{
  std::cout << "Hello, world!" << std::endl;
}

And all is fine.

But now, I want to add some Unit test of my library. So I need to find/compile/link the "fcdk" library. So I change the main.cc file to this one:

#include <iostream>
#include <fcdk/CommandLineOptionFlag.h>

int
main()
{
  FCDK::CommandLineOptionFlag show_help('h', "help", "show this help message");
  std::cout << "Hello, world!" << std::endl;
}

Here the CMakeLists.txt of the test_package directory:

cmake_minimum_required(VERSION 3.2)
project(FcdkTest CXX)


include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)


add_executable(
  test-fcdk
  main.cc
)
target_include_directories(test-fcdk PUBLIC ${CONAN_INCLUDE_DIRS_FCDK})
target_link_libraries(test-fcdk PUBLIC ${CONAN_LIBS_FCDK})
target_link_libraries(test-fcdk PUBLIC CONAN_PKG::fcdk)

enable_testing()
add_test(NAME test-fcdk
         WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin
         COMMAND test-fcdk)

And the conan recipe:

import os
from conans import ConanFile, CMake, tools


class FcdkTestConan(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    generators = "cmake"
    requires = "fcdk/1.0.0"

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def test(self):
        if not tools.cross_building(self.settings):
            os.chdir("bin")
            self.run(".%stest-fcdk" % os.sep)

I could not achieve the test_package to link correctly.

CMakeFiles/test-fcdk.dir/main.cc.o: In function `FCDK::CommandLineOptionFlag::accept(FCDK::VisitorBase&)':
main.cc:(.text._ZN4FCDK21CommandLineOptionFlag6acceptERNS_11VisitorBaseE[_ZN4FCDK21CommandLineOptionFlag6acceptERNS_11VisitorBaseE]+0xa1): undefined reference to `FCDK::demangleTypename(char const*)'
main.cc:(.text._ZN4FCDK21CommandLineOptionFlag6acceptERNS_11VisitorBaseE[_ZN4FCDK21CommandLineOptionFlag6acceptERNS_11VisitorBaseE]+0xdd): undefined reference to `FCDK::demangleTypename(char const*)'
CMakeFiles/test-fcdk.dir/main.cc.o: In function `main':
main.cc:(.text.startup+0x5e): undefined reference to `FCDK::CommandLineOptionFlag::CommandLineOptionFlag(char, std::string, std::string)'

All the previous step:

conan source 
conan install
conan build
conan package
conan export-pkg

was fine and seems correct to me. I put here the content of the conan package command:

package/
package/conaninfo.txt
package/include
package/include/fcdk
package/include/fcdk/Exception.h
package/include/fcdk/CommandLineOption.h
package/include/fcdk/CommandLineOptionWithValue.h
package/include/fcdk/Visitor.h
package/include/fcdk/ABI.h
package/include/fcdk/CommandLineParser.h
package/include/fcdk/CommandLineOptionFlag.h
package/conanmanifest.txt
package/lib
package/lib/libfcdk.a
package/share
package/share/cmake
package/share/cmake/fcdk
package/share/cmake/fcdk/fcdkTargets.cmake
package/share/cmake/fcdk/fcdkTargets-release.cmake

I've also look at the missing symbol in the libfcdk.a For example:

                 U FCDK::demangleTypename[abi:cxx11](char const*)
                 U FCDK::demangleTypename[abi:cxx11](char const*)
0000000000000000 t _GLOBAL__sub_I__ZN4FCDK16demangleTypenameB5cxx11EPKc
0000000000000000 T FCDK::demangleTypename[abi:cxx11](char const*)

When I run the make with VERBOSE=1, I do not see the fcdk library information on the link command

/usr/bin/cmake -E cmake_link_script CMakeFiles/test-fcdk.dir/link.txt --verbose=1
/usr/bin/c++   -m64 -O3 -DNDEBUG  -rdynamic CMakeFiles/test-fcdk.dir/main.cc.o  -o bin/test-fcdk 
CMakeFiles/test-fcdk.dir/main.cc.o: In function `FCDK::CommandLineOptionFlag::accept(FCDK::VisitorBase&)':

Could someone help me to figure out whay the test_pacakge recipe does not link agains my fcdk/1.0.0 package please ?

Thank you very much

EDIT: Conan repository with test_pacakge updated https://github.com/lmarzull/fcdk-conan/tree/devel



Solution 1:[1]

First of all, many thanks to @ymochurad

He points me to filling the self.cpp_info.libs with the name of the given library.

But one this was done, the story continue. I need to modify

test_package/CMakeLists.txt test_package/conanfile.py

# conanfile.py
def package_info(self):
  self.cpp_info.libs = [ "fcdk" ]

And

# test_package/CMakeLists.txt
FIND_PACKAGE(fcdk REQUIRED)

# remove conan_basic_setup(TARGETS)
# and replace with:
conan_basic_setup()

# Add ${CONAN_INCLUDE_DIRS}
target_include_directories(test-fcdk
  PRIVATE ${CONAN_INCLUDE_DIRS})

# and also fcdk_LIBRARIES in link directive
target_link_libraries(test-fcdk ${fcdk_LIBRARIES})

And

# test_package/conanfile.py
def config_options(self):
  self.settings.compiler.libcxx = "libstdc++11"

All of those modifications resolve the initial problem.

Solution 2:[2]

The point of the test_package folder is that, if it contains a conanfile.py with a test() function, Conan will automatically handle it once the package is fully created.


Note: Windows specifics have been omitted for simplicity.

Starting from the following basic project structure:

.
??? CMakeLists.txt
??? conanfile.py
??? src
?   ??? mylib.cpp
?   ??? mylib.hpp
??? test_package
    ??? CMakeLists.txt
    ??? conanfile.py
    ??? main.cpp

Top-level CMakeLists.txt:

cmake_minimum_required(VERSION 3.13)
project(mylib)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

add_library(${PROJECT_NAME} src/mylib.cpp src/mylib.hpp)
conan_target_link_libraries(${PROJECT_NAME}) // Note the conan_ prefix here

// This will automatically install at the right place depending on the platform
// e.g. a .DLL file goes to bin while .SO/.A/.LIB files go to lib
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME})
install(DIRECTORY src/
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}
        FILES_MATCHING PATTERN "*.hpp")

Top-level conanfile.py:

from conans import ConanFile, CMake


class MylibConan(ConanFile):
    name            = "mylib"
    version         = "1.0.0"
    settings        = "os", "compiler", "build_type", "arch"
    options         = {"shared": [True, False], "fPIC": [True, False]}
    default_options = {"shared": False, "fPIC": True}
    generators      = "cmake"
    exports_sources = "src/*", "CMakeLists.txt"

    def _cmake(self):
        if not hasattr(self, 'cmake'):
            self.cmake = CMake(self)
            self.cmake.configure()

        return self.cmake

    def build(self):
        self._cmake().build()

    def package(self):
        self._cmake().install()

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

test_package/main.cpp:

#include <mylib/mylib.hpp>

int main()
{
    mylib();
}

test_package/CMakeLists.txt:

cmake_minimum_required(VERSION 3.13)
project(unit-test)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

add_executable(${PROJECT_NAME} main.cpp)
conan_target_link_libraries(${PROJECT_NAME})

test_package/conanfile.py:

from conans import ConanFile, CMake


class MylibTestConan(ConanFile):
    settings   = "os", "compiler", "build_type", "arch"
    generators = "cmake"
    # No explicit requires of the top-level library, Conan does it by itself!

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def test(self):
        self.run("bin/unit-test")

Now you can call conan create . and your test_package will automatically get built and run in your local directory.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Gojita
Solution 2 Chnossos