Skip to content

Commit

Permalink
(#4776) protobuf: allow shared on Macos + add protobuf::protoc import…
Browse files Browse the repository at this point in the history
…ed target

* really provide protobuf::protoc target

* cosmetic change

* simplify check of runtime

* properly handle protobuf with zlib

previous injection of lib directories was too fragile.
It breaks as soon as there is a dependency

* append to builddirs

* cleanup

* fix semicolon replacement

* more robust DYLD_LIBRARY_PATH injection

* cosmetic change

* improve runtime handling

* no protobuf_BUILD_LIBPROTOC option before 3.14.0

* honor upstream default value for with_zlib

* add protobuf/3.15.4

* provide Protobuf_PROTOC_EXECUTABLE CACHE variable

* trick to no break pkg_config generator internal handling in conan

* workaround for invalid-constexpr with clang

* clang < 4 not supported in recent protobuf

* cleanup

* do not disable rtti by default

* Revert "workaround for invalid-constexpr with clang"

This reverts commit dc170c4.

* remove useless test of find_program

* use TARGET_FILE in apple patch

* add 3.15.5 instead of 3.15.4

* add rtti option if protobuf >= 3.15.4

* removed duplicated version

* empty commit

* keep find_program protoc logic for cross compilation
  • Loading branch information
SpaceIm committed Mar 23, 2021
1 parent ae64779 commit 7cf61ab
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 87 deletions.
16 changes: 8 additions & 8 deletions recipes/protobuf/all/conandata.yml
@@ -1,21 +1,21 @@
sources:
3.9.1:
"3.9.1":
sha256: 98e615d592d237f94db8bf033fba78cd404d979b0b70351a9e5aaff725398357
url: https://github.com/protocolbuffers/protobuf/archive/v3.9.1.tar.gz
3.11.4:
"3.11.4":
sha256: a79d19dcdf9139fa4b81206e318e33d245c4c9da1ffed21c87288ed4380426f9
url: https://github.com/protocolbuffers/protobuf/archive/v3.11.4.tar.gz
3.12.4:
"3.12.4":
sha256: 512e5a674bf31f8b7928a64d8adf73ee67b8fe88339ad29adaa3b84dbaa570d8
url: https://github.com/protocolbuffers/protobuf/archive/v3.12.4.tar.gz
3.13.0:
"3.13.0":
sha256: 9b4ee22c250fe31b16f1a24d61467e40780a3fbb9b91c3b65be2a376ed913a1a
url: https://github.com/protocolbuffers/protobuf/archive/v3.13.0.tar.gz
3.15.5:
"3.15.5":
sha256: bc3dbf1f09dba1b2eb3f2f70352ee97b9049066c9040ce0c9b67fb3294e91e4b
url: https://github.com/protocolbuffers/protobuf/archive/v3.15.5.tar.gz
patches:
3.12.4:
"3.12.4":
- patch_file: "patches/upstream-pr-7761-cmake-regex-fix.patch"
base_path: "source_subfolder"
- patch_file: "patches/upstream-issue-7567-no-export-template-define.patch"
Expand All @@ -24,13 +24,13 @@ patches:
base_path: "source_subfolder"
- patch_file: "patches/upstream-pr-8301-bundle-destination.patch"
base_path: "source_subfolder"
3.13.0:
"3.13.0":
- patch_file: "patches/upstream-pr-7761-cmake-regex-fix.patch"
base_path: "source_subfolder"
- patch_file: "patches/upstream-pr-7288-android-log.patch"
base_path: "source_subfolder"
- patch_file: "patches/upstream-pr-8301-bundle-destination.patch"
base_path: "source_subfolder"
3.15.5:
"3.15.5":
- patch_file: "patches/upstream-pr-8301-bundle-destination.patch"
base_path: "source_subfolder"
150 changes: 77 additions & 73 deletions recipes/protobuf/all/conanfile.py
@@ -1,7 +1,7 @@
import os
from conans import ConanFile, CMake, tools
from conans.errors import ConanInvalidConfiguration
from conans.tools import Version
import os
import textwrap


class ProtobufConan(ConanFile):
Expand All @@ -12,25 +12,27 @@ class ProtobufConan(ConanFile):
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/protocolbuffers/protobuf"
license = "BSD-3-Clause"
exports_sources = ["CMakeLists.txt", "patches/*"]
generators = "cmake"
short_paths = True

settings = "os", "arch", "compiler", "build_type"
options = {
"fPIC": [True, False],
"lite": [True, False],
"shared": [True, False],
"fPIC": [True, False],
"with_zlib": [True, False],
"with_rtti": [True, False],
"with_zlib": [True, False]
"lite": [True, False],
}
default_options = {
"fPIC": True,
"lite": False,
"shared": False,
"fPIC": True,
"with_zlib": True,
"with_rtti": True,
"with_zlib": False
"lite": False,
}

short_paths = True

exports_sources = ["CMakeLists.txt", "patches/*"]
generators = "cmake"
_cmake = None

@property
Expand All @@ -49,11 +51,6 @@ def _is_clang_x86(self):
def _can_disable_rtti(self):
return tools.Version(self.version) >= "3.15.4"

def source(self):
tools.get(**self.conan_data["sources"][self.version])
extracted_folder = self.name + "-" + self.version
os.rename(extracted_folder, self._source_subfolder)

def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
Expand All @@ -64,14 +61,11 @@ def configure(self):
if self.options.shared:
del self.options.fPIC

if self.settings.os == "Windows" and self.settings.compiler in ["Visual Studio", "clang"] and "MT" in self.settings.compiler.runtime:
if str(self.settings.compiler.get_safe("runtime")) in ["MT", "MTd", "static"]:
raise ConanInvalidConfiguration("Protobuf can't be built with shared + MT(d) runtimes")

if tools.is_apple_os(self.settings.os):
raise ConanInvalidConfiguration("Protobuf could not be built as shared library for Mac.")

if self.settings.compiler == "Visual Studio":
if Version(self.settings.compiler.version) < "14":
if tools.Version(self.settings.compiler.version) < "14":
raise ConanInvalidConfiguration("On Windows Protobuf can only be built with "
"Visual Studio 2015 or higher.")

Expand All @@ -83,6 +77,11 @@ def requirements(self):
if self.options.with_zlib:
self.requires("zlib/1.2.11")

def source(self):
tools.get(**self.conan_data["sources"][self.version])
extracted_folder = self.name + "-" + self.version
os.rename(extracted_folder, self._source_subfolder)

@property
def _cmake_install_base_path(self):
return os.path.join("lib", "cmake", "protobuf")
Expand All @@ -94,69 +93,81 @@ def _configure_cmake(self):
self._cmake.definitions["protobuf_WITH_ZLIB"] = self.options.with_zlib
self._cmake.definitions["protobuf_BUILD_TESTS"] = False
self._cmake.definitions["protobuf_BUILD_PROTOC_BINARIES"] = True
self._cmake.definitions["protobuf_BUILD_LIBPROTOC"] = True
if tools.Version(self.version) >= "3.14.0":
self._cmake.definitions["protobuf_BUILD_LIBPROTOC"] = True
if self._can_disable_rtti:
self._cmake.definitions["protobuf_DISABLE_RTTI"] = not self.options.with_rtti
if self.settings.compiler == "Visual Studio":
self._cmake.definitions["protobuf_MSVC_STATIC_RUNTIME"] = "MT" in str(self.settings.compiler.runtime)
if self.settings.compiler.get_safe("runtime"):
self._cmake.definitions["protobuf_MSVC_STATIC_RUNTIME"] = str(self.settings.compiler.runtime) in ["MT", "MTd", "static"]
self._cmake.configure(build_folder=self._build_subfolder)
return self._cmake

def _patch_sources(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
tools.patch(**patch)

find_protoc = """
# Find the protobuf compiler within the paths added by Conan, for use below.
find_program(PROTOC_PROGRAM protoc PATHS ENV PATH NO_DEFAULT_PATH)
if(NOT PROTOC_PROGRAM)
set(PROTOC_PROGRAM "protoc")
endif()
"""
# Provide relocatable protobuf::protoc target and Protobuf_PROTOC_EXECUTABLE cache variable
# TODO: some of the following logic might be disabled when conan will
# allow to create executable imported targets in package_info()
protobuf_config_cmake = os.path.join(self._source_subfolder, "cmake", "protobuf-config.cmake.in")

tools.replace_in_file(
os.path.join(self._source_subfolder, "cmake", "protobuf-config.cmake.in"),
protobuf_config_cmake,
"@_protobuf_FIND_ZLIB@",
"# CONAN PATCH _protobuf_FIND_ZLIB@"
"# BEGIN CONAN PATCH\n#_protobuf_FIND_ZLIB@\n# END CONAN PATCH"
)

exe_ext = ".exe" if self.settings.os == "Windows" else ""
protoc_filename = "protoc" + exe_ext
module_folder_depth = len(os.path.normpath(self._cmake_install_base_path).split(os.path.sep))
protoc_rel_path = "{}bin/{}".format("".join(["../"] * module_folder_depth), protoc_filename)
protoc_target = textwrap.dedent("""\
if(NOT TARGET protobuf::protoc)
find_program(PROTOC_PROGRAM protoc PATHS ENV PATH NO_DEFAULT_PATH)
if(NOT PROTOC_PROGRAM)
set(PROTOC_PROGRAM \"${{CMAKE_CURRENT_LIST_DIR}}/{protoc_rel_path}\")
endif()
get_filename_component(PROTOC_PROGRAM \"${{PROTOC_PROGRAM}}\" ABSOLUTE)
set(Protobuf_PROTOC_EXECUTABLE ${{PROTOC_PROGRAM}} CACHE FILEPATH \"The protoc compiler\")
add_executable(protobuf::protoc IMPORTED)
set_property(TARGET protobuf::protoc PROPERTY IMPORTED_LOCATION ${{Protobuf_PROTOC_EXECUTABLE}})
endif()
""".format(protoc_rel_path=protoc_rel_path))
tools.replace_in_file(
os.path.join(self._source_subfolder, "cmake", "protobuf-config.cmake.in"),
protobuf_config_cmake,
"include(\"${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake\")",
"# CONAN PATCH include(\"${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake\")" + find_protoc
protoc_target
)

if tools.Version(self.version) < "3.12.0":
# Set DYLD_LIBRARY_PATH in command line to avoid issues with shared protobuf
# (even with virtualrunenv, this fix might be required due to SIP)
# Only works with cmake, cmake_find_package or cmake_find_package_multi generators
if tools.is_apple_os(self.settings.os):
tools.replace_in_file(
os.path.join(self._source_subfolder, "cmake", "protobuf-config.cmake.in"),
"""COMMAND protobuf::protoc
ARGS --${protobuf_generate_LANGUAGE}_out ${_dll_export_decl}${protobuf_generate_PROTOC_OUT_DIR} ${_protobuf_include_path} ${_abs_file}
DEPENDS ${_abs_file} protobuf::protoc""",
"""COMMAND "${CMAKE_COMMAND}"
ARGS -E env "DYLD_LIBRARY_PATH=${Protobuf_LIB_DIRS}:${CONAN_LIB_DIRS}:${Protobuf_LIB_DIRS_RELEASE}:${Protobuf_LIB_DIRS_DEBUG}:${Protobuf_LIB_DIRS_RELWITHDEBINFO}:${Protobuf_LIB_DIRS_MINSIZEREL}" ${PROTOC_PROGRAM} --${protobuf_generate_LANGUAGE}_out ${_dll_export_decl}${protobuf_generate_PROTOC_OUT_DIR} ${_protobuf_include_path} ${_abs_file}
DEPENDS ${_abs_file} USES_TERMINAL"""
protobuf_config_cmake,
"add_custom_command(",
("set(CUSTOM_DYLD_LIBRARY_PATH ${CONAN_LIB_DIRS} ${Protobuf_LIB_DIRS} ${Protobuf_LIB_DIRS_RELEASE} ${Protobuf_LIB_DIRS_DEBUG} ${Protobuf_LIB_DIRS_RELWITHDEBINFO} ${Protobuf_LIB_DIRS_MINSIZEREL})\n"
"string(REPLACE \";\" \":\" CUSTOM_DYLD_LIBRARY_PATH \"${CUSTOM_DYLD_LIBRARY_PATH}\")\n"
"add_custom_command(")
)
else:
tools.replace_in_file(
os.path.join(self._source_subfolder, "cmake", "protobuf-config.cmake.in"),
"""COMMAND protobuf::protoc
ARGS --${protobuf_generate_LANGUAGE}_out ${_dll_export_decl}${protobuf_generate_PROTOC_OUT_DIR} ${_plugin} ${_protobuf_include_path} ${_abs_file}
DEPENDS ${_abs_file} protobuf::protoc""",
"""COMMAND "${CMAKE_COMMAND}"
ARGS -E env "DYLD_LIBRARY_PATH=${Protobuf_LIB_DIRS}:${CONAN_LIB_DIRS}:${Protobuf_LIB_DIRS_RELEASE}:${Protobuf_LIB_DIRS_DEBUG}:${Protobuf_LIB_DIRS_RELWITHDEBINFO}:${Protobuf_LIB_DIRS_MINSIZEREL}" ${PROTOC_PROGRAM} --${protobuf_generate_LANGUAGE}_out ${_dll_export_decl}${protobuf_generate_PROTOC_OUT_DIR} ${_plugin} ${_protobuf_include_path} ${_abs_file}
DEPENDS ${_abs_file} USES_TERMINAL"""
protobuf_config_cmake,
"COMMAND protobuf::protoc",
"COMMAND ${CMAKE_COMMAND} -E env \"DYLD_LIBRARY_PATH=${CUSTOM_DYLD_LIBRARY_PATH}\" $<TARGET_FILE:protobuf::protoc>"
)

# Disable a potential warning in protobuf-module.cmake.in
# TODO: remove this patch? Is it really useful?
protobuf_module_cmake = os.path.join(self._source_subfolder, "cmake", "protobuf-module.cmake.in")
tools.replace_in_file(
os.path.join(self._source_subfolder, "cmake", "protobuf-module.cmake.in"),
'if(DEFINED Protobuf_SRC_ROOT_FOLDER)',
"""if(0)
if(DEFINED Protobuf_SRC_ROOT_FOLDER)""",
protobuf_module_cmake,
"if(DEFINED Protobuf_SRC_ROOT_FOLDER)",
"if(0)\nif(DEFINED Protobuf_SRC_ROOT_FOLDER)",
)
tools.replace_in_file(
os.path.join(self._source_subfolder, "cmake", "protobuf-module.cmake.in"),
'# Define upper case versions of output variables',
'endif()',
protobuf_module_cmake,
"# Define upper case versions of output variables",
"endif()",
)

def build(self):
Expand Down Expand Up @@ -186,6 +197,7 @@ def package_info(self):

self.cpp_info.names["cmake_find_package"] = "protobuf"
self.cpp_info.names["cmake_find_package_multi"] = "protobuf"
self.cpp_info.names["pkg_config"] = "protobuf_full_package" # unofficial, but required to avoid side effects (libprotobuf component "steals" the default global pkg_config name)

lib_prefix = "lib" if self.settings.compiler == "Visual Studio" else ""
lib_suffix = "d" if self.settings.build_type == "Debug" else ""
Expand All @@ -205,25 +217,17 @@ def package_info(self):
if self.settings.os == "Windows":
if self.options.shared:
self.cpp_info.components["libprotobuf"].defines = ["PROTOBUF_USE_DLLS"]

self.cpp_info.components["libprotobuf"].builddirs = [
self._cmake_install_base_path,
]

self.cpp_info.components["libprotobuf"].builddirs = [self._cmake_install_base_path]
self.cpp_info.components["libprotobuf"].build_modules.extend([
self.cpp_info.components["libprotobuf"].builddirs.append(self._cmake_install_base_path)
self.cpp_info.components["libprotobuf"].build_modules = [
os.path.join(self._cmake_install_base_path, "protobuf-generate.cmake"),
os.path.join(self._cmake_install_base_path, "protobuf-module.cmake"),
os.path.join(self._cmake_install_base_path, "protobuf-options.cmake"),
])
]

self.cpp_info.components["libprotoc"].name = "libprotoc"
self.cpp_info.components["libprotoc"].libs = [lib_prefix + "protoc" + lib_suffix]
self.cpp_info.components["libprotoc"].requires = ["libprotobuf"]

self.cpp_info.components["protoc"].name = "protoc"
self.cpp_info.components["protoc"].requires.extend(["libprotoc", "libprotobuf"])

bindir = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH environment variable: {}".format(bindir))
self.env_info.PATH.append(bindir)
Expand All @@ -243,9 +247,9 @@ def package_info(self):
if self.settings.os == "Android":
self.cpp_info.components["libprotobuf-lite"].system_libs.append("log")

self.cpp_info.components["libprotobuf-lite"].builddirs = [self._cmake_install_base_path]
self.cpp_info.components["libprotobuf-lite"].build_modules.extend([
self.cpp_info.components["libprotobuf-lite"].builddirs.append(self._cmake_install_base_path)
self.cpp_info.components["libprotobuf-lite"].build_modules = [
os.path.join(self._cmake_install_base_path, "protobuf-generate.cmake"),
os.path.join(self._cmake_install_base_path, "protobuf-module.cmake"),
os.path.join(self._cmake_install_base_path, "protobuf-options.cmake"),
])
]
2 changes: 1 addition & 1 deletion recipes/protobuf/all/test_package/conanfile.py
@@ -1,4 +1,4 @@
from conans import ConanFile, CMake, RunEnvironment, tools
from conans import ConanFile, CMake, tools
import os


Expand Down
10 changes: 5 additions & 5 deletions recipes/protobuf/config.yml
@@ -1,11 +1,11 @@
versions:
3.9.1:
"3.9.1":
folder: all
3.11.4:
"3.11.4":
folder: all
3.12.4:
"3.12.4":
folder: all
3.13.0:
"3.13.0":
folder: all
3.15.5:
"3.15.5":
folder: all

0 comments on commit 7cf61ab

Please sign in to comment.