conan-io / conan

Conan - The open-source C and C++ package manager
https://conan.io
MIT License
8.27k stars 981 forks source link

[question] libftdi1 issues loading dylib #8628

Closed matte86 closed 5 days ago

matte86 commented 3 years ago

Hey guys,

Sorry if this was asked several times but I read all examples and conan documentation but still haven't figured out how to fix this.

I am running conan 1.34.0 on MacOSX and working on an application for which I would like to consume libftdi. In the conan center unfortunately the version is rather old (0.20).

I am trying to create a package using libftdi1. Following the recipe for the version 0.20 and the conan documentation on creating packages I managed to compile and create the package in my local cache. This is the package recipe.

from conans import ConanFile, CMake, tools
import os

class LibFtdi1Conan(ConanFile):
    name = "libftdi1"
    description = "libFTDI - FTDI USB driver with bitbang mode"
    url = "https://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.5.tar.bz2"
    license = "LGPL-2.0"
    version = "1.5"
    exports_sources = "CMakeLists.txt", "patches/**"
    settings = "os", "arch", "compiler", "build_type"
    options = {
        "shared": [True, False],
        "fPIC": [True, False],
        "enable_cpp_wrapper": [True, False],
    }
    default_options = {
        "shared": True,
        "fPIC": True,
        "enable_cpp_wrapper": False,
    }
    generators = "cmake", "cmake_find_package"
    source_subfolder = "libftdi1-{}".format(version)

    _cmake = None

    def config_options(self):
        if self.settings.os == "Windows":
            del self.options.fPIC

    def configure(self):
        if self.options.shared:
            del self.options.fPIC
        if not self.options.enable_cpp_wrapper:
            del self.settings.compiler.libcxx
            del self.settings.compiler.cppstd

    def source(self):
        tools.get(self.url)

    def requirements(self):
        self.requires("libusb/1.0.24")
        self.requires("libconfuse/3.3")

        if self.options.enable_cpp_wrapper:
            self.requires("boost/1.75.0")

    def _configure_cmake(self):
        if self._cmake:
            return self._cmake
        self._cmake = CMake(self)
        self._cmake.definitions["FTDIPP"] = self.options.enable_cpp_wrapper
        self._cmake.definitions["PYTHON_BINDINGS"] = False
        self._cmake.definitions["EXAMPLES"] = False
        self._cmake.definitions["DOCUMENTATION"] = False
        self._cmake.configure(source_dir=self.source_subfolder)
        return self._cmake

    def _patch_sources(self):
        tools.replace_in_file(os.path.join(self.source_subfolder, "CMakeLists.txt"), "CMAKE_BINARY_DIR", "PROJECT_BINARY_DIR")
        tools.replace_in_file(os.path.join(self.source_subfolder, "CMakeLists.txt"), "CMAKE_SOURCE_DIR", "PROJECT_SOURCE_DIR")
        tools.replace_in_file(os.path.join(self.source_subfolder, "ftdipp", "CMakeLists.txt"), "CMAKE_SOURCE_DIR", "PROJECT_SOURCE_DIR")

        # Patching files for proper build with conan
        find_confuse_pkg_file = "./" + self.source_subfolder + "/cmake/FindConfuse.cmake"
        find_usb1_pkg_file = "./" + self.source_subfolder + "/cmake/FindUSB1.cmake"
        os.remove(find_confuse_pkg_file)
        os.remove(find_usb1_pkg_file)
        os.rename("./Findlibconfuse.cmake", find_confuse_pkg_file)
        os.rename("./Findlibusb.cmake", find_usb1_pkg_file)
        tools.replace_in_file(os.path.join(self.source_subfolder, "CMakeLists.txt"), "project(libftdi1 C)",
                              '''project(libftdi1 C)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()''')
        tools.replace_in_file(os.path.join(self.source_subfolder, "src","CMakeLists.txt"), "target_link_libraries(ftdi1 ${LIBUSB_LIBRARIES})",
                              '''target_link_libraries(ftdi1 ${LIBUSB_LIBRARIES} ${CONAN_LIBS})''')

    def build(self):
        self._patch_sources()
        cmake = self._configure_cmake()
        cmake.build()

    def package(self):
        self.copy(pattern="COPYING*", src=self.source_subfolder, dst="licenses")
        cmake = self._configure_cmake()
        cmake.install()

        tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))

    def package_info(self):
        if self.options.enable_cpp_wrapper:
            self.cpp_info.libs.append("ftdipp1")
        self.cpp_info.libs.append("ftdi1")

The application also builds fine, this is my conanfile:

from conans import ConanFile, CMake

class ExampleConan(ConanFile):
  settings = ('os', 'compiler', 'build_type', 'arch')
  requires = (
    'gtest/1.8.1@bincrafters/stable',
    'libftdi1/1.5@build/testing'
  )
  generators = 'cmake'

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

  def imports(self):
    self.copy('*.dll', src='bin', dst='bin')
    self.copy('*.dylib*', src='lib', dst='lib')
    self.copy('*.so', src='lib', dst='lib')

Unfortunately, when I try to run the binary I receive the following error:

dyld: Library not loaded: libftdi1.2.dylib

I know I am probably messing up with rpaths and dynamic linkage. If I inspect the binary with otool I get:

otool -L bin/UnitTests bin/UnitTests: libftdi1.2.dylib (compatibility version 2.0.0, current version 2.5.0) /Users/miname/.conan/data/libpq/11.5///package/629b9f80b519063e4c405aab7332f604318faa5b/lib/libpq.5.dylib (compatibility version 5.0.0, current version 5.11.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1) ...

From this I see that libpq, another library that my application depends on and that I do not build myself, points to the library in my local conan cache; libftdi1 on the other hand, that I build myself, does not contain the full path to the dylib.

Apparently the issue is already present when I build the conan package myself for libftdi1; if I build libftdi1 examples I get the same problem on the dynamic library linkage. The vanilla libftdi1 repo is not meant to be built with conan so I am perhaps missing something in the integration conan - cmake. I read all the documentation I could but I am running out of ideas. Could someone help?

matte86 commented 3 years ago

I actually noted that there is a pull request 3957 pending for this.

memsharded commented 3 years ago

Hi @agn0stico

Have you tried with the latest recipe contributed in https://github.com/conan-io/conan-center-index/pull/3957? If you checkout the contributors branch and create the package from there, you could try their package, maybe it fixes the issue? If it does, commenting on that PR in ConanCenter will also be good.

matte86 commented 3 years ago

Hi @memsharded

thanks for following up on this. I actually tried what you suggested but it seem I am having the same issue when building a shared library with that package as well.

I am running Mac OS 10.15.7, conan 1.34.0 and cmake 3.17.3.

memsharded commented 5 days ago

Sorry this was not followed up.

I am closing this ticket as outdated, using legacy cmake_find_package generator, already removed in Conan 2 time ago.

Please don't hesitate to open new tickets for any further question.