Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net-snmp: migrate to Conan v2 #19227

Merged
merged 22 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions recipes/net-snmp/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
sources:
"5.9.1":
sha256: "75b59d67e871aaaa31c8cef89ba7d06972782b97736b7e8c3399f36b50a8816f"
url: https://sourceforge.net/projects/net-snmp/files/net-snmp/5.9.1/net-snmp-5.9.1.zip/download
"5.9.4":
url: "https://sourceforge.net/projects/net-snmp/files/net-snmp/5.9.4/net-snmp-5.9.4.zip/download"
sha256: "ceea0c876f23b87731de2073e6a3a683ea610c66a5a67b5cabf4986b7813c22b"
patches:
"5.9.1":
"5.9.4":
- patch_file: patches/0001-fix-openssl-linking-msvc.patch
base_path: ""
patch_description: "Use Conan OpenSSL when linking on Windows"
patch_source: "https://github.com/net-snmp/net-snmp/commit/99332c80b68248cb60023d12297135dc9c6c8abf"
- patch_file: patches/0002-install-only-libnetsnmp.patch
base_path: ""
patch_description: "Avoid install extra helper libraries"
- patch_file: patches/0003-fix-perl-scripts-msvc.patch
base_path: ""
- patch_file: patches/0004-fix-apple-arm64-build.patch
base_path: ""
patch_description: "Avoid injecting extra flags when running perl"
277 changes: 151 additions & 126 deletions recipes/net-snmp/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import functools
import os
import stat

from conans import AutoToolsBuildEnvironment, ConanFile, tools
from conans.errors import ConanInvalidConfiguration
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.build import cross_building
from conan.tools.env import VirtualRunEnv
from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, replace_in_file, rm, rmdir, chdir
from conan.tools.gnu import Autotools, AutotoolsDeps, AutotoolsToolchain, PkgConfigDeps
from conan.tools.layout import basic_layout
from conan.tools.microsoft import is_msvc, msvc_runtime_flag, NMakeToolchain
from conan.tools.apple import is_apple_os, fix_apple_shared_install_name

required_conan_version = ">=1.43.0"
required_conan_version = ">=1.53.0"


class NetSnmpConan(ConanFile):
Expand All @@ -15,10 +21,12 @@ class NetSnmpConan(ConanFile):
"for monitoring the health and welfare of network equipment "
"(eg. routers), computer equipment and even devices like UPSs."
)
license = "BSD-3-Clause"
url = "https://github.com/conan-io/conan-center-index"
homepage = "http://www.net-snmp.org/"
topics = "snmp"
license = "BSD-3-Clause"

package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
Expand All @@ -30,167 +38,184 @@ class NetSnmpConan(ConanFile):
"fPIC": True,
"with_ipv6": True,
}
requires = "openssl/1.1.1m"
exports_sources = "patches/*"

@property
def _is_msvc(self):
return self.settings.compiler in ("Visual Studio", "msvc")

def validate(self):
if self.settings.os == "Windows" and not self._is_msvc:
raise ConanInvalidConfiguration(
"net-snmp is setup to build only with MSVC on Windows"
)

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

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

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

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

def requirements(self):
self.requires("openssl/[>=1.1 <4]")
self.requires("pcre/8.45")
self.requires("zlib/[>=1.2.11 <2]")
uilianries marked this conversation as resolved.
Show resolved Hide resolved

def validate(self):
if is_msvc(self) and self.options.shared:
# FIXME: Linker errors against third-party dependencies:
# snmp_openssl.obj : error LNK2019: unresolved external symbol CRYPTO_free referenced in function _extract_oname
raise ConanInvalidConfiguration(f"{self.ref} fails when building as shared library, use -o '&:shared=False'. Contributions are welcome!")

def build_requirements(self):
if self._is_msvc:
self.build_requires("strawberryperl/5.30.0.1")
if is_msvc(self):
self.tool_requires("strawberryperl/5.32.1.1")
else:
self.tool_requires("gnu-config/cci.20210814")
self.tool_requires("autoconf/2.71")
self.tool_requires("automake/1.16.5")
self.tool_requires("libtool/2.4.7")
if not self.conf.get("tools.gnu:pkg_config", default=False, check_type=str):
self.tool_requires("pkgconf/2.2.0")

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

@property
def _is_debug(self):
return self.settings.build_type == "Debug"

def generate(self):
if is_msvc(self):
tc = NMakeToolchain(self)
tc.generate()
# Workaround for "unresolved external symbol" errors during shared build
env = VirtualRunEnv(self)
env.generate(scope="build")
else:
if not cross_building(self):
env = VirtualRunEnv(self)
env.generate(scope="build")
tc = AutotoolsToolchain(self)
debug_flag = "enable" if self._is_debug else "disable"
ipv6_flag = "enable" if self.options.with_ipv6 else "disable"
openssl_path = self.dependencies["openssl"].package_folder
zlib_path = self.dependencies["zlib"].package_folder
tc.configure_args += [
f"--with-openssl={openssl_path}",
f"--with-zlib={zlib_path}",
f"--{debug_flag}-debugging",
f"--{ipv6_flag}-ipv6",
"--with-defaults",
"--without-rpm",
"--without-pcre",
"--disable-agent",
"--disable-applications",
"--disable-manuals",
"--disable-scripts",
"--disable-mibs",
"--disable-embedded-perl",
]
if self.settings.os in ["Linux"]:
tc.extra_ldflags.append("-ldl")
tc.extra_ldflags.append("-lpthread")
tc.generate()

deps = AutotoolsDeps(self)
deps.generate()

deps = PkgConfigDeps(self)
deps.generate()

def _patch_msvc(self):
ssl_info = self.deps_cpp_info["openssl"]
openssl_root = ssl_info.rootpath.replace("\\", "/")
ssl_info = self.dependencies["openssl"]
openssl_root = ssl_info.package_folder.replace("\\", "/")
search_replace = [
(
r'$default_openssldir . "\\include"',
f"'{openssl_root}/include'"
),
(r'$default_openssldir . "\\include"', f"'{openssl_root}/include'"),
(r'$default_openssldir . "\\lib\\VC"', f"'{openssl_root}/lib'"),
("$openssl = false", "$openssl = true")
("$openssl = false", "$openssl = true"),
]
if self._is_debug:
search_replace.append(("$debug = false", "$debug = true"))
if self.options.shared:
search_replace.append((
"$link_dynamic = false",
"$link_dynamic = true"
))
search_replace.append(("$link_dynamic = false", "$link_dynamic = true"))
if self.options.with_ipv6:
search_replace.append(("$b_ipv6 = false", "$b_ipv6 = true"))
for search, replace in search_replace:
tools.replace_in_file("win32\\build.pl", search, replace)
runtime = self.settings.compiler.runtime
tools.replace_in_file("win32\\Configure", '"/runtime', f'"/{runtime}')
replace_in_file(self, "build.pl", search, replace)
replace_in_file(self, "Configure", '"/runtime', f'"/{msvc_runtime_flag(self)}')
link_lines = "\n".join(
f'# pragma comment(lib, "{lib}.lib")'
for lib in ssl_info.libs + ssl_info.system_libs
for lib in ssl_info.cpp_info.libs + ssl_info.cpp_info.system_libs
)
config = r"win32\net-snmp\net-snmp-config.h.in"
tools.replace_in_file(config, "/* Conan: system_libs */", link_lines)

def _build_msvc(self):
if self.should_configure:
self._patch_msvc()
self.run("perl build.pl", cwd="win32")
if self.should_build:
with tools.vcvars(self):
self.run("nmake /nologo libsnmp", cwd="win32")

@functools.lru_cache(1)
def _configure_autotools(self):
disabled_link_type = "static" if self.options.shared else "shared"
debug_flag = "enable" if self._is_debug else "disable"
ipv6_flag = "enable" if self.options.with_ipv6 else "disable"
ssl_path = self.deps_cpp_info["openssl"].rootpath
args = [
"--with-defaults",
"--without-rpm",
"--without-pcre",
"--disable-agent",
"--disable-applications",
"--disable-manuals",
"--disable-scripts",
"--disable-mibs",
"--disable-embedded-perl",
f"--disable-{disabled_link_type}",
f"--{debug_flag}-debugging",
f"--{ipv6_flag}-ipv6",
f"--with-openssl={ssl_path}",
]
autotools = AutoToolsBuildEnvironment(self)
autotools.libs = []
autotools.configure(args=args)
return autotools
config = r"net-snmp\net-snmp-config.h.in"
replace_in_file(self, config, "/* Conan: system_libs */", link_lines)

def _patch_unix(self):
tools.replace_in_file(
"configure",
"-install_name \\$rpath/",
"-install_name @rpath/"
)
crypto_libs = self.deps_cpp_info["openssl"].system_libs
for gnu_config in [
self.conf.get("user.gnu-config:config_guess", check_type=str),
self.conf.get("user.gnu-config:config_sub", check_type=str),
]:
if gnu_config:
copy(self, os.path.basename(gnu_config), src=os.path.dirname(gnu_config), dst=self.source_folder)
configure_path = os.path.join(self.source_folder, "configure")
replace_in_file(self, configure_path,
"-install_name \\$rpath/",
"-install_name @rpath/")
crypto_libs = self.dependencies["openssl"].cpp_info.system_libs
if len(crypto_libs) != 0:
crypto_link_flags = " -l".join(crypto_libs)
tools.replace_in_file(
"configure",
replace_in_file(self, configure_path,
'LIBCRYPTO="-l${CRYPTO}"',
'LIBCRYPTO="-l${CRYPTO} -l%s"' % (crypto_link_flags,)
)
tools.replace_in_file(
"configure",
'LIBS="-lcrypto $LIBS"',
f'LIBS="-lcrypto -l{crypto_link_flags} $LIBS"'
)
'LIBCRYPTO="-l${CRYPTO} -l%s"' % (crypto_link_flags,))
replace_in_file(self, configure_path,
'LIBS="-lcrypto $LIBS"',
f'LIBS="-lcrypto -l{crypto_link_flags} $LIBS"')

def build(self):
for patch in self.conan_data["patches"][self.version]:
tools.patch(**patch)
if self._is_msvc:
self._build_msvc()
apply_conandata_patches(self)
if is_msvc(self):
with chdir(self, os.path.join(self.source_folder, "win32")):
self._patch_msvc()
self.run("perl build.pl")
self.run("nmake /nologo libsnmp")
else:
self._patch_unix()
os.chmod("configure", os.stat("configure").st_mode | stat.S_IEXEC)
self._configure_autotools()\
.make(target="snmplib", args=["NOAUTODEPS=1"])

def _package_msvc(self):
cfg = "debug" if self._is_debug else "release"
self.copy("netsnmp.dll", "bin", fr"win32\bin\{cfg}")
self.copy("netsnmp.lib", "lib", fr"win32\lib\{cfg}")
self.copy("include/net-snmp/*.h")
for directory in ["", "agent/", "library/"]:
self.copy(f"net-snmp/{directory}*.h", "include", "win32")
self.copy("COPYING", "licenses")

def _remove(self, path):
if os.path.isdir(path):
tools.rmdir(path)
else:
os.remove(path)

def _package_unix(self):
self._configure_autotools().install(args=["NOAUTODEPS=1"])
tools.remove_files_by_mask(self.package_folder, "README")
tools.rmdir(os.path.join(self.package_folder, "bin"))
lib_dir = os.path.join(self.package_folder, "lib")
for entry in os.listdir(lib_dir):
if not entry.startswith("libnetsnmp.") or entry.endswith(".la"):
self._remove(os.path.join(lib_dir, entry))
self.copy("COPYING", "licenses")
configure_path = os.path.join(self.source_folder, "configure")
os.chmod(configure_path, os.stat(configure_path).st_mode | stat.S_IEXEC)
autotools = Autotools(self)
autotools.autoreconf()
autotools.configure()
autotools.make(target="snmplib", args=["NOAUTODEPS=1"])

def package(self):
if self._is_msvc:
self._package_msvc()
copy(self, "COPYING",
dst=os.path.join(self.package_folder, "licenses"),
src=self.source_folder)
if is_msvc(self):
cfg = "debug" if self._is_debug else "release"
copy(self, "netsnmp.lib",
dst=os.path.join(self.package_folder, "lib"),
src=os.path.join(self.source_folder, rf"win32\lib\{cfg}"))
copy(self, "include/net-snmp/*.h",
dst=self.package_folder,
src=self.source_folder)
for directory in ["", "agent/", "library/"]:
copy(self, f"net-snmp/{directory}*.h",
dst=os.path.join(self.package_folder, "include"),
src=os.path.join(self.source_folder, "win32"))
else:
self._package_unix()
autotools = Autotools(self)
#only install with -j1 as parallel install will break dependencies. Probably a bug in the dependencies
#install specific targets instead of just everything as it will try to do perl stuff on you host machine
autotools.install(args=["-j1"], target="installsubdirs installlibs installprogs installheaders")
rm(self, "README", self.package_folder, recursive=True)
rmdir(self, os.path.join(self.package_folder, "bin"))
rm(self, "*.la", self.package_folder, recursive=True)
fix_apple_shared_install_name(self)

def package_info(self):
self.cpp_info.libs = ["netsnmp"]
self.cpp_info.requires = ["openssl::openssl"]
if self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.system_libs.extend(["rt", "pthread", "m"])
if is_apple_os(self):
self.cpp_info.frameworks.extend(["CoreFoundation", "DiskArbitration", "IOKit"])
Loading
Loading