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

openssl: let openssl create FindOpenSSL.cmake script equivalent to official #486

Closed
wants to merge 3 commits into from
Closed
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
30 changes: 0 additions & 30 deletions recipes/openssl/ALL/test_package/CMakeLists.txt

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from conans.errors import ConanInvalidConfiguration, ConanException
from conans import ConanFile, AutoToolsBuildEnvironment, tools
from contextlib import contextmanager
import os
import fnmatch
import platform
from functools import total_ordering
from conans.errors import ConanInvalidConfiguration, ConanException
from conans import ConanFile, AutoToolsBuildEnvironment, tools


@total_ordering
Expand Down Expand Up @@ -94,8 +95,9 @@ class OpenSSLConan(ConanFile):
default_options = {key: False for key in options.keys()}
default_options["fPIC"] = True
default_options["openssldir"] = None
exports_sources = "openssl_extra.cmake"
_env_build = None
_source_subfolder = "sources"
_source_subfolder = "source_subfolder"

def build_requirements(self):
# useful for example for conditional build_requires
Expand Down Expand Up @@ -136,16 +138,19 @@ def source(self):
extracted_folder = "openssl-" + self.version
os.rename(extracted_folder, self._source_subfolder)

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

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

def configure(self):
if self.options.shared:
del self.options.fPIC

del self.settings.compiler.libcxx
del self.settings.compiler.cppstd

def requirements(self):
if not self.options.no_zlib:
self.requires("zlib/1.2.11")
Expand Down Expand Up @@ -459,6 +464,10 @@ def _perl(self):
return os.path.join(self.deps_cpp_info["strawberryperl"].rootpath, "bin", "perl.exe")
return "perl"

@property
def _nmake_makefile(self):
return r"ms\ntdll.mak" if self.options.shared else r"ms\nt.mak"

def _make(self):
with tools.chdir(self._source_subfolder):
# workaround for MinGW (https://github.com/openssl/openssl/issues/7653)
Expand All @@ -479,19 +488,16 @@ def _make(self):
self.run(r"ms\do_nasm")
else:
self.run(r"ms\do_ms" if self.settings.arch == "x86" else r"ms\do_win64a")
makefile = r"ms\ntdll.mak" if self.options.shared else r"ms\nt.mak"

self._replace_runtime_in_file(os.path.join("ms", "nt.mak"))
self._replace_runtime_in_file(os.path.join("ms", "ntdll.mak"))
if self.settings.arch == "x86":
tools.replace_in_file(os.path.join("ms", "nt.mak"), "-WX", "")
tools.replace_in_file(os.path.join("ms", "ntdll.mak"), "-WX", "")

self._run_make(makefile=makefile)
self._run_make(makefile=makefile, targets=["install"], parallel=False)
self._run_make(makefile=self._nmake_makefile)
else:
self._run_make()
self._run_make(targets=["install_sw"], parallel=False)

@property
def _cc(self):
Expand All @@ -507,7 +513,8 @@ def _cc(self):
return "gcc"
return "cc"

def build(self):
@contextmanager
def _build_environment(self):
with tools.vcvars(self.settings) if self._use_nmake else tools.no_op():
env_vars = {"PERL": self._perl}
if self._full_version < "1.1.0":
Expand All @@ -518,11 +525,15 @@ def build(self):
env_vars["CROSS_SDK"] = os.path.basename(xcrun.sdk_path)
env_vars["CROSS_TOP"] = os.path.dirname(os.path.dirname(xcrun.sdk_path))
with tools.environment_append(env_vars):
if self._full_version >= "1.1.0":
self._create_targets()
else:
self._patch_makefile_org()
self._make()
yield

def build(self):
with self._build_environment():
if self._full_version >= "1.1.0":
self._create_targets()
else:
self._patch_makefile_org()
self._make()

@staticmethod
def detected_os():
Expand Down Expand Up @@ -569,7 +580,28 @@ def _replace_runtime_in_file(self, filename):
for e in ["MDd", "MTd", "MD", "MT"]:
tools.replace_in_file(filename, "/%s " % e, "/%s " % self.settings.compiler.runtime, strict=False)

@property
def _find_cmake_dict(self):
ssl, crypto = self._ssl_crypto_library
return {
"@CONAN_SSL_LIBRARY@": ssl,
"@CONAN_CRYPTO_LIBRARY@": crypto,
}

def package(self):
cmake_text = open("openssl_extra.cmake").read()
for key, value in self._find_cmake_dict.items():
cmake_text = cmake_text.replace(key, value)
cmake_dir = os.path.join(self.package_folder, "lib", "cmake", "openssl")
tools.mkdir(cmake_dir)
open(os.path.join(cmake_dir, "openssl_extra.cmake"), "w").write(cmake_text)
with self._build_environment():
with tools.chdir(self._source_subfolder):
if self._use_nmake and self._full_version < "1.1.0":
self._run_make(makefile=self._nmake_makefile, targets=["install"], parallel=False)
else:
self._run_make(targets=["install_sw"], parallel=False)

self.copy(src=self._source_subfolder, pattern="*LICENSE", dst="licenses")
for root, _, files in os.walk(self.package_folder):
for filename in files:
Expand All @@ -588,19 +620,25 @@ def package(self):
os.chmod("libcrypto.so.1.0.0", 0o755)
tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))

def package_info(self):
self.cpp_info.name = "OpenSSL"
@property
def _ssl_crypto_library(self):
if self._use_nmake:
if self._full_version < "1.1.0":
self.cpp_info.libs = ["ssleay32", "libeay32"]
return "ssleay32", "libeay32"
else:
if self.settings.build_type == "Debug":
self.cpp_info.libs = ['libssld', 'libcryptod']
return "libssld", "libcryptod"
else:
self.cpp_info.libs = ['libssl', 'libcrypto']
return "libssl", "libcrypto"
else:
self.cpp_info.libs = ["ssl", "crypto"]
return "ssl", "crypto"

def package_info(self):
self.cpp_info.name = "OpenSSL"
self.cpp_info.libs = [*self._ssl_crypto_library]
if self.settings.os == "Windows":
self.cpp_info.libs.extend(["crypt32", "msi", "ws2_32", "advapi32", "user32", "gdi32"])
self.cpp_info.system_libs.extend(["crypt32", "msi", "ws2_32", "advapi32", "user32", "gdi32"])
elif self.settings.os == "Linux":
self.cpp_info.libs.extend(["dl", "pthread"])
self.cpp_info.system_libs.extend(["dl", "pthread"])
self.cpp_info.build_modules = [os.path.join("lib", "cmake", "openssl", "openssl_extra.cmake")]
self.cpp_info.builddirs = [os.path.join("lib", "cmake", "openssl")]
45 changes: 45 additions & 0 deletions recipes/openssl/all/openssl_extra.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# This script should only run when included in a FindXXX.cmake module
if(NOT OpenSSL_LIB_DIRS)
return()
endif()

# library names of crypto and ssl libraries
set(CONAN_CRYPTO_LIBRARY "@CONAN_CRYPTO_LIBRARY@")
set(CONAN_SSL_LIBRARY "@CONAN_SSL_LIBRARY@")

# absolute paths of crypto and ssl libraries
find_library(CONAN_CRYPTO_ABSOLUTE_LIBRARY NAME ${CONAN_CRYPTO_LIBRARY} PATHS ${OpenSSL_LIB_DIRS} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
find_library(CONAN_SSL_ABSOLUTE_LIBRARY NAME ${CONAN_SSL_LIBRARY} PATHS ${OpenSSL_LIB_DIRS} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)

# https://cmake.org/cmake/help/latest/module/FindOpenSSL.html

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is probably a good idea to call find_package_handle_standard_args (https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html) to report the error if the files could not be found and set some of the variables that are set in the next few lines.

There is more documentation on regarding writing finders in https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/How-To-Find-Libraries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea about find_package_handle_standard_args.


set(OPENSSL_FOUND ON)
set(OPENSSL_INCLUDE_DIR ${OpenSSL_INCLUDE_DIRS})
set(OPENSSL_LIBRARIES ${OpenSSL_LIBRARIES} ${OpenSSL_SYSTEM_LIBS})
set(OPENSSL_VERSION "${OpenSSL_VERSION}")

set(OPENSSL_CRYPTO_LIBRARY ${CONAN_CRYPTO_ABSOLUTE_LIBRARY})
set(OPENSSL_CRYPTO_LIBRARIES ${CONAN_CRYPTO_ABSOLUTE_LIBRARY} ${OpenSSL_SYSTEM_LIBS})
set(OPENSSL_SSL_LIBRARY ${CONAN_CRYPTO_ABSOLUTE_LIBRARY})
set(OPENSSL_SSL_LIBRARIES ${CONAN_CRYPTO_ABSOLUTE_LIBRARY} ${OpenSSL_SYSTEM_LIBS})

if(NOT CMAKE_VERSION VERSION_LESS 3.0)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are conan recipes targeting cmake versions older than 3.0 (cmake 3 was released in 2014 https://cmake.org/pipermail/cmake/2014-June/057793.html)? Maybe people using conan are using a reasonably recent version of cmake? Is that a valid assumption?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just copied the same logic as the FindXXX.cmake files generated by conan.

But more generally, I believe conan should add a feature for cmake_find_package and cmake_find_package_multi. As this pull request won't co-operate well with the multi-generator.

conan would need a feature that allows this:

def package_info(self):
    self.cpp_info.name = "OpenSSL"
    self.cpp_info.libs = [*self._ssl_crypto_library]
    system_libs = []
    if self.settings.os == "Windows":
        system_libs.extend(["crypt32", "msi", "ws2_32", "advapi32", "user32", "gdi32"])
    elif self.settings.os == "Linux":
        system_libs.extend(["dl", "pthread"])
    self.cpp_info.system_libs.extend(system_libs)

    # By default: the generated cmake targets should inherit the dependencies of this recipe
    ssl_system_libs = ["crypt32", "msi", "ws2_32", "advapi32", "user32", "gdi32"]
    crypto_system_libs = ["crypt32", "msi", "advapi32", "user32", "gdi32"]
    for generator in ("cmake_find_package", "cmake_find_package_multi"):
        ssl_library, crypto_library = self._ssl_crypto_library

        # Set OPENSSL_FOUND unconditionally, is a string by default
        self.cpp_info.generators[generator].add_variable("OPENSSL_FOUND", "ON")
        self.cpp_info.generators[generator].add_variable("OPENSSL_VERSION", self.version, type=CMakeVariableType.String)

        # Add OPENSSL_SSL_LIBRARIES variable: it will be set by find_library calls + is genex ==> will be a generator expression when generator == cmake_find_package_multi
        sslLibraryVariable = self.cpp_info.generators[generator].add_variable("OPENSSL_SSL_LIBRARY", self._ssl_library, type=CMakeVariableType.Library, genex=True)

        sslCMakeTarget = self.cpp_info.generators[generator].createCMakeTarget("OpenSSL::SSL")
        # - override libraries
        sslCMakeTarget.libs = [ssl_library]
        # - override system libraries (SSL requires different system_libs then crypto)
        sslCMakeTarget.system_libs = ssl_system_libs
        # - inherit include directories
        # sslCMakeTarget.includedirs = ["include"]
        # - inherit package dependencies (so in CMake, link to all dependencies (CONAN_PKG::dep1, CONAN_PKG_dep2)
        # sslCMakeTarget.deps = ["dep1", "dep2"]
        # - inherit defines
        # sslCMakeTarget.defines = []
        # - inherit link flags
        # sslCMakeTarget.linkflags = []

        # Add OPENSSL_SSL_LIBRARIES variable: it will be set by find_library calls + is genex ==> will be a generator expression when generator == cmake_find_package_multi
        cryptoLibraryVariable = self.cpp_info.generators[generator].add_variable("OPENSSL_CRYPTO_LIBRARY", self._crypto_library, type=CMakeVariableType.Library, genex=True)

        cryptoCMakeTarget = self.cpp_info.generators[generator].createCMakeTarget("OpenSSL::Crypto")
        cryptoCMakeTarget.libs = [crypto_library]
        cryptoCMakeTarget.system_libs = crypto_system_libs
        # inherit other variables ....

        # Add OPENSSL_LIBRARIES: it will be a list of these variables (which can be cmake variables themselves) + is gen_ex
        self.cpp_info.generators[generator].add_variable("OPENSSL_LIBRARIES", [sslLibraryVariable, cryptoLibraryVariable] + system_libs, type=CMakeVariableType.List, genex=True)

        # Add OPENSSL_INCLUDE_DIR variable: is a path + generator expression
        self.cpp_info.generators[generator].add_variable("OPENSSL_INCLUDE_DIR", os.path.join(self.package_folder, "include"), type=CMakeVariableType.Path, genex=True)

The setting of variables might need some dependency tracking (optionally), but I think this interface can serve a lot of use cases.

if(NOT TARGET OpenSSL::Crypto)
add_library(OpenSSL::Crypto INTERFACE IMPORTED)
if(OpenSSL_INCLUDE_DIRS)
set_target_properties(OpenSSL::Crypto PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OpenSSL_INCLUDE_DIRS}")
endif()
set_property(TARGET OpenSSL::Crypto PROPERTY INTERFACE_LINK_LIBRARIES ${CONAN_CRYPTO_ABSOLUTE_LIBRARY} ${OpenSSL_SYSTEM_LIBS} "${OpenSSL_LINKER_FLAGS_LIST}")
set_property(TARGET OpenSSL::Crypto PROPERTY INTERFACE_COMPILE_DEFINITIONS ${OpenSSL_COMPILE_DEFINITIONS})
set_property(TARGET OpenSSL::Crypto PROPERTY INTERFACE_COMPILE_OPTIONS "${OpenSSL_COMPILE_OPTIONS_LIST}")
endif()
if(NOT TARGET OpenSSL::SSL)
add_library(OpenSSL::SSL INTERFACE IMPORTED)
if(OpenSSL_INCLUDE_DIRS)
set_target_properties(OpenSSL::SSL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OpenSSL_INCLUDE_DIRS}")
endif()
set_property(TARGET OpenSSL::SSL PROPERTY INTERFACE_LINK_LIBRARIES ${CONAN_SSL_ABSOLUTE_LIBRARY} ${OpenSSL_SYSTEM_LIBS} "${OpenSSL_LINKER_FLAGS_LIST}")
set_property(TARGET OpenSSL::SSL PROPERTY INTERFACE_COMPILE_DEFINITIONS ${OpenSSL_COMPILE_DEFINITIONS})
set_property(TARGET OpenSSL::SSL PROPERTY INTERFACE_COMPILE_OPTIONS "${OpenSSL_COMPILE_OPTIONS_LIST}")
endif()
endif()
42 changes: 42 additions & 0 deletions recipes/openssl/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
PROJECT(test_package)
cmake_minimum_required(VERSION 2.8)

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

add_executable(digest digest.cpp)

if(USE_FIND_PACKAGE)
set(OpenSSL_DEBUG 1)
find_package(OpenSSL REQUIRED)
message("LINK WITH ${OPENSSL_LIBRARIES}")

target_include_directories(digest PRIVATE ${OPENSSL_INCLUDE_DIRS})
target_link_libraries(digest ${OPENSSL_LIBRARIES})

find_package(Threads)
target_link_libraries(digest PRIVATE ${CMAKE_THREAD_LIBS_INIT})

if(WIN32)
target_link_libraries(digest PRIVATE ws2_32 crypt32)
endif()
if(UNIX AND NOT APPLE)
target_link_libraries(digest PRIVATE ${CMAKE_DL_LIBS})
endif()

add_executable(test_crypto test_crypto.cpp)
target_link_libraries(test_crypto OpenSSL::Crypto)

add_executable(test_crypto_bad EXCLUDE_FROM_ALL test_crypto.cpp)
target_link_libraries(test_crypto OpenSSL::SSL)

add_executable(test_ssl test_ssl.c)
target_link_libraries(test_ssl OpenSSL::SSL)

add_executable(test_ssl_bad EXCLUDE_FROM_ALL test_ssl.c)
target_link_libraries(test_ssl OpenSSL::Crypto)
else()
message("LINK WITH ${CONAN_LIBS}")
target_include_directories(digest PRIVATE ${CONAN_INCLUDE_DIRS})
target_link_libraries(digest PRIVATE ${CONAN_LIBS})
endif()
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
from conans import CMake, tools, ConanFile
from conans.errors import ConanException
import os


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

def _build_cmake(self, use_find_package):
cmake = CMake(self)
Expand All @@ -20,6 +20,13 @@ def _build_cmake(self, use_find_package):

cmake.configure()
cmake.build()
if use_find_package:
for bad_target in ("test_crypto_bad", "test_ssl_bad"):
try:
cmake.build(target=bad_target)
assert False
except ConanException:
pass

def build(self):
self._build_cmake(use_find_package=True)
Expand All @@ -29,4 +36,8 @@ def test(self):
if not tools.cross_building(self.settings):
bin_path = os.path.join("bin", "digest")
self.run(bin_path, run_environment=True)
bin_path = os.path.join("bin", "test_crypto")
self.run(bin_path, run_environment=True)
bin_path = os.path.join("bin", "test_ssl")
self.run(bin_path, run_environment=True)
assert os.path.exists(os.path.join(self.deps_cpp_info["openssl"].rootpath, "licenses", "LICENSE"))
Loading