Skip to content

Commit

Permalink
(#13131) odbc: conan v2 support + unvendor libltdl
Browse files Browse the repository at this point in the history
* conan v2 support

* handle system libs deps of libltdl

* fix ODR violation between odbc & odbccr

* fix duplicated symbol in 2.3.11
  • Loading branch information
SpaceIm authored Sep 30, 2022
1 parent a484011 commit f9825b2
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 76 deletions.
8 changes: 6 additions & 2 deletions recipes/odbc/all/conandata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ sources:
- "http://www.unixodbc.net/unixODBC-2.3.7.tar.gz"
sha256: "45f169ba1f454a72b8fcbb82abd832630a3bf93baa84731cf2949f449e1e3e77"
patches:
"2.3.11":
- patch_file: "patches/0001-duplicated-get-connection.patch"
"2.3.9":
- patch_file: "patches/0001-duplicated-get-connection.patch"
"2.3.7":
- patch_file: "patches/missing-declarations.patch"
base_path: "source_subfolder"
- patch_file: "patches/0001-duplicated-get-connection.patch"
- patch_file: "patches/0002-missing-declarations.patch"
132 changes: 77 additions & 55 deletions recipes/odbc/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from conans import ConanFile, AutoToolsBuildEnvironment, tools
from conans.errors import ConanInvalidConfiguration
import functools
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, replace_in_file, rm, rmdir
from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.layout import basic_layout
import os
import shutil

required_conan_version = ">=1.43.0"
required_conan_version = ">=1.52.0"


class OdbcConan(ConanFile):
Expand All @@ -27,84 +29,106 @@ class OdbcConan(ConanFile):
"with_libiconv": True,
}

@property
def _source_subfolder(self):
return "source_subfolder"

@property
def _user_info_build(self):
return getattr(self, "user_info_build", self.deps_user_info)

def export_sources(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
self.copy(patch["patch_file"])
export_conandata_patches(self)

def configure(self):
if self.options.shared:
del self.options.fPIC
del self.settings.compiler.libcxx
del self.settings.compiler.cppstd
try:
del self.options.fPIC
except Exception:
pass
try:
del self.settings.compiler.cppstd
except Exception:
pass
try:
del self.settings.compiler.libcxx
except Exception:
pass

def layout(self):
basic_layout(self, src_folder="src")

def requirements(self):
self.requires("libtool/2.4.7")
if self.options.with_libiconv:
self.requires("libiconv/1.17")

def validate(self):
if self.settings.os == "Windows":
if self.info.settings.os == "Windows":
raise ConanInvalidConfiguration("odbc is a system lib on Windows")

def build_requirements(self):
self.build_requires("gnu-config/cci.20201022")
self.tool_requires("gnu-config/cci.20210814")

def source(self):
tools.get(**self.conan_data["sources"][self.version],
destination=self._source_subfolder, strip_root=True)
get(self, **self.conan_data["sources"][self.version],
destination=self.source_folder, strip_root=True)

def generate(self):
tc = AutotoolsToolchain(self)
yes_no = lambda v: "yes" if v else "no"
tc.configure_args.extend([
"--without-included-ltdl",
f"--with-ltdl-include={self.dependencies['libtool'].cpp_info.includedirs[0]}",
f"--with-ltdl-lib={self.dependencies['libtool'].cpp_info.libdirs[0]}",
"--disable-ltdl-install",
f"--enable-iconv={yes_no(self.options.with_libiconv)}",
"--sysconfdir=/etc",
])
if self.options.with_libiconv:
libiconv_prefix = self.dependencies["libiconv"].package_folder
tc.configure_args.append(f"--with-libiconv-prefix={libiconv_prefix}")
tc.generate()

def _patch_sources(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
tools.patch(**patch)
apply_conandata_patches(self)
# support more triplets
shutil.copy(self._user_info_build["gnu-config"].CONFIG_SUB,
os.path.join(self._source_subfolder, "config.sub"))
os.path.join(self.source_folder, "config.sub"))
shutil.copy(self._user_info_build["gnu-config"].CONFIG_GUESS,
os.path.join(self._source_subfolder, "config.guess"))
os.path.join(self.source_folder, "config.guess"))
# allow external libtdl (in libtool recipe)
replace_in_file(
self,
os.path.join(self.source_folder, "configure"),
"if test -f \"$with_ltdl_lib/libltdl.la\";",
"if true;",
)
libtool_system_libs = self.dependencies["libtool"].cpp_info.system_libs
if libtool_system_libs:
replace_in_file(
self,
os.path.join(self.source_folder, "configure"),
"-L$with_ltdl_lib -lltdl",
"-L$with_ltdl_lib -lltdl -l{}".format(" -l".join(libtool_system_libs)),
)
# relocatable shared libs on macOS
for configure in [
os.path.join(self._source_subfolder, "configure"),
os.path.join(self._source_subfolder, "libltdl", "configure"),
os.path.join(self.source_folder, "configure"),
os.path.join(self.source_folder, "libltdl", "configure"),
]:
tools.replace_in_file(configure, "-install_name \\$rpath/", "-install_name @rpath/")

@functools.lru_cache(1)
def _configure_autotools(self):
autotools = AutoToolsBuildEnvironment(self)
autotools.libs = []
yes_no = lambda v: "yes" if v else "no"
args = [
"--enable-shared={}".format(yes_no(self.options.shared)),
"--enable-static={}".format(yes_no(not self.options.shared)),
"--enable-ltdl-install",
"--enable-iconv={}".format(yes_no(self.options.with_libiconv)),
"--sysconfdir=/etc",
]
if self.options.with_libiconv:
libiconv_prefix = self.deps_cpp_info["libiconv"].rootpath
args.append("--with-libiconv-prefix={}".format(libiconv_prefix))
autotools.configure(configure_dir=self._source_subfolder, args=args)
return autotools
replace_in_file(self, configure, "-install_name \\$rpath/", "-install_name @rpath/")

def build(self):
self._patch_sources()
autotools = self._configure_autotools()
autotools = Autotools(self)
autotools.configure()
autotools.make()

def package(self):
self.copy("COPYING", src=self._source_subfolder, dst="licenses")
autotools = self._configure_autotools()
copy(self, "COPYING", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
autotools = Autotools(self)
autotools.install()
tools.rmdir(os.path.join(self.package_folder, "share"))
tools.rmdir(os.path.join(self.package_folder, "etc"))
tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))
tools.remove_files_by_mask(os.path.join(self.package_folder, "lib"), "*.la")
rmdir(self, os.path.join(self.package_folder, "share"))
rmdir(self, os.path.join(self.package_folder, "etc"))
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rm(self, "*.la", os.path.join(self.package_folder, "lib"))

def package_info(self):
self.cpp_info.set_property("cmake_find_mode", "both")
Expand All @@ -119,26 +143,24 @@ def package_info(self):
# odbc
self.cpp_info.components["_odbc"].set_property("pkg_config_name", "odbc")
self.cpp_info.components["_odbc"].libs = ["odbc"]
self.cpp_info.components["_odbc"].requires = ["odbcltdl"]
self.cpp_info.components["_odbc"].requires = ["libtool::libtool"]
if self.options.with_libiconv:
self.cpp_info.components["_odbc"].requires.append("libiconv::libiconv")

# odbcinst
self.cpp_info.components["odbcinst"].set_property("pkg_config_name", "odbcinst")
self.cpp_info.components["odbcinst"].libs = ["odbcinst"]
self.cpp_info.components["odbcinst"].requires = ["odbcltdl"]
self.cpp_info.components["odbcinst"].requires = ["libtool::libtool"]

# odbccr
self.cpp_info.components["odbccr"].set_property("pkg_config_name", "odbccr")
self.cpp_info.components["odbccr"].libs = ["odbccr"]

self.cpp_info.components["odbcltdl"].libs = ["ltdl"]

if self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.components["_odbc"].system_libs = ["pthread"]
self.cpp_info.components["odbcinst"].system_libs = ["pthread"]
self.cpp_info.components["odbcltdl"].system_libs = ["dl"]

# TODO: to remove in conan v2
bin_path = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH environment variable: {}".format(bin_path))
self.output.info(f"Appending PATH environment variable: {bin_path}")
self.env_info.PATH.append(bin_path)
11 changes: 11 additions & 0 deletions recipes/odbc/all/patches/0001-duplicated-get-connection.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- a/cur/SQLGetDiagRec.c
+++ b/cur/SQLGetDiagRec.c
@@ -101,8 +101,4 @@ SQLRETURN CLGetDiagRec( SQLSMALLINT handle_type,
text_length_ptr);
}

-DMHDBC __get_connection( EHEAD * head )
-{
- return 0;
-}

7 changes: 2 additions & 5 deletions recipes/odbc/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
cmake_minimum_required(VERSION 3.1)
project(test_package C)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
project(test_package LANGUAGES C)

find_package(ODBC REQUIRED)

add_executable(${PROJECT_NAME} test_package.c)
target_link_libraries(${PROJECT_NAME} ODBC::ODBC)
target_link_libraries(${PROJECT_NAME} PRIVATE ODBC::ODBC)
28 changes: 14 additions & 14 deletions recipes/odbc/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
from conans import ConanFile, CMake, tools
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import CMake, cmake_layout
import os


class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "cmake", "cmake_find_package"
generators = "CMakeToolchain", "CMakeDeps", "VirtualRunEnv"
test_type = "explicit"

def build_requirements(self):
if self.settings.os == "Macos" and self.settings.arch == "armv8":
# Workaround for CMake bug with error message:
# Attempting to use @rpath without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being
# set. This could be because you are using a Mac OS X version less than 10.5
# or because CMake's platform configuration is corrupt.
# FIXME: Remove once CMake on macOS/M1 CI runners is upgraded.
self.build_requires("cmake/3.22.0")
def layout(self):
cmake_layout(self)

def requirements(self):
self.requires(self.tested_reference_str)

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

def test(self):
if not tools.cross_building(self):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
self.run("odbcinst --version", run_environment=True)
if can_run(self):
bin_path = os.path.join(self.cpp.build.bindirs[0], "test_package")
self.run(bin_path, env="conanrun")
self.run("odbcinst --version", env="conanrun")
10 changes: 10 additions & 0 deletions recipes/odbc/all/test_v1_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.1)
project(test_package LANGUAGES C)

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

find_package(ODBC REQUIRED)

add_executable(${PROJECT_NAME} ../test_package/test_package.c)
target_link_libraries(${PROJECT_NAME} PRIVATE ODBC::ODBC)
18 changes: 18 additions & 0 deletions recipes/odbc/all/test_v1_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from conans import ConanFile, CMake, tools
import os


class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "cmake", "cmake_find_package"

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

def test(self):
if not tools.cross_building(self):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
self.run("odbcinst --version", run_environment=True)

0 comments on commit f9825b2

Please sign in to comment.