Skip to content

Commit

Permalink
(#4849) leptonica: fix CMake imported target + honor options + add wi…
Browse files Browse the repository at this point in the history
…th_zlib option

* refactoring of leptonica recipe

- add with_zlib option
- use classic CMake wrapper
- rely on pkgconf for openjpeg & libwep dependencies, it's more robust
- do not use CMAKE_DISABLE_FIND_PACKAGE_<LIB> to honor options, it's too fragile and might break due to find_package required in find module of others dependencies also requiring those libs
- several cosmetic changes

* move fixes specific to 1.78.0 in a patch

* fix CMake imported target

* more agressive patch for openjpeg & libwebp

avoid to enable openjpeg or libwebp if found in system, but options disabled by consumers

* fix dependencies injection again

- be sure to inject dependencies definitions
- use pkg_config only for libwebp & openjpeg
  • Loading branch information
SpaceIm committed Mar 13, 2021
1 parent 54564eb commit 3ee8a20
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 107 deletions.
4 changes: 2 additions & 2 deletions recipes/leptonica/all/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.1)
project(cmake_wrapper)

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

include("CMakeListsOriginal.txt")
add_subdirectory(source_subfolder)
4 changes: 4 additions & 0 deletions recipes/leptonica/all/conandata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ sources:
"1.80.0":
url: "https://github.com/DanBloomberg/leptonica/archive/1.80.0.tar.gz"
sha256: "3952b974ec057d24267aae48c54bca68ead8275604bf084a73a4b953ff79196e"
patches:
"1.78.0":
- patch_file: "patches/fix-find-modules-variables.patch"
base_path: "source_subfolder"
265 changes: 165 additions & 100 deletions recipes/leptonica/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,68 @@
from conans import ConanFile, CMake, tools
import os
import shutil
import textwrap

required_conan_version = ">=1.33.0"


class LeptonicaConan(ConanFile):
name = "leptonica"
url = "https://github.com/conan-io/conan-center-index"
description = "Library containing software that is broadly useful for image processing and image analysis applications."
description = "Library containing software that is broadly useful for " \
"image processing and image analysis applications."
topics = ("conan", "leptonica", "image", "multimedia", "format", "graphics")
settings = "os", "compiler", "build_type", "arch"
generators = "cmake", "cmake_find_package"
homepage = "http://leptonica.org"
license = "BSD 2-Clause"
exports_sources = ["CMakeLists.txt"]

options = {"shared": [True, False],
"with_gif": [True, False],
"with_jpeg": [True, False],
"with_png": [True, False],
"with_tiff": [True, False],
"with_openjpeg": [True, False],
"with_webp": [True, False],
"fPIC": [True, False]
}
default_options = {'shared': False,
'with_gif': False,
'with_jpeg': True,
'with_png': True,
'with_tiff': True,
'with_openjpeg': True,
'with_webp': True,
'fPIC': True}

settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"with_zlib": [True, False],
"with_gif": [True, False],
"with_jpeg": [True, False],
"with_png": [True, False],
"with_tiff": [True, False],
"with_openjpeg": [True, False],
"with_webp": [True, False]
}
default_options = {
"shared": False,
"fPIC": True,
"with_zlib": True,
"with_gif": True,
"with_jpeg": True,
"with_png": True,
"with_tiff": True,
"with_openjpeg": True,
"with_webp": True
}

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

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

@property
def _build_subfolder(self):
return "build_subfolder"

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

def requirements(self):
self.requires("zlib/1.2.11")
if self.options.with_zlib:
self.requires("zlib/1.2.11")
if self.options.with_gif:
self.requires("giflib/5.2.1")
if self.options.with_jpeg:
Expand All @@ -50,106 +76,145 @@ def requirements(self):
if self.options.with_webp:
self.requires("libwebp/1.1.0")

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

def configure(self):
del self.settings.compiler.libcxx
del self.settings.compiler.cppstd
def build_requirements(self):
if self.options.with_webp or self.options.with_openjpeg:
self.build_requires("pkgconf/1.7.3")

def source(self):
tools.get(**self.conan_data["sources"][self.version])
extracted_dir = self.name + "-" + self.version
os.rename(extracted_dir, self._source_subfolder)
# Leptonica is very sensitive to package layout
# so use source directory same as _source_subfolder
os.rename(os.path.join(self._source_subfolder, "CMakeLists.txt"),
os.path.join(self._source_subfolder, "CMakeListsOriginal.txt"))
shutil.copy("CMakeLists.txt",
os.path.join(self._source_subfolder, "CMakeLists.txt"))

def _configure_cmake(self):
if self._cmake:
return self._cmake
cmake = self._cmake = CMake(self)
if self.version == '1.78.0':
cmake.definitions['STATIC'] = not self.options.shared
cmake.definitions['BUILD_PROG'] = False
# avoid finding system libs
cmake.definitions['CMAKE_DISABLE_FIND_PACKAGE_GIF'] = not self.options.with_gif
cmake.definitions['CMAKE_DISABLE_FIND_PACKAGE_PNG'] = not self.options.with_png
cmake.definitions['CMAKE_DISABLE_FIND_PACKAGE_TIFF'] = not self.options.with_tiff
cmake.definitions['CMAKE_DISABLE_FIND_PACKAGE_JPEG'] = not self.options.with_jpeg

cmake.definitions['SW_BUILD'] = False

cmake.configure(source_folder=self._source_subfolder)
return cmake

def build(self):
cmake_original = os.path.join(self._source_subfolder,
"CMakeListsOriginal.txt")
# disable pkgconfig
tools.replace_in_file(cmake_original,
"if (PKG_CONFIG_FOUND)",
"if (FALSE)")

# short out conditionals that don't respect
# CMAKE_DISABLE_FIND_PACKAGE_x
if not self.options.with_webp:
tools.replace_in_file(cmake_original,
"if(NOT WEBP)",
"if(FALSE)")
tools.replace_in_file(cmake_original,
"if(NOT WEBPMUX)",
"if(FALSE)")
def _patch_sources(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
tools.patch(**patch)

cmakelists = os.path.join(self._source_subfolder, "CMakeLists.txt")
cmakelists_src = os.path.join(self._source_subfolder, "src", "CMakeLists.txt")
cmake_configure = os.path.join(self._source_subfolder, "cmake", "Configure.cmake")

# Fix installation
tools.replace_in_file(cmakelists_src, "${CMAKE_BINARY_DIR}", "${PROJECT_BINARY_DIR}")

# Honor options and inject dependencies definitions
# TODO: submit a patch upstream
## zlib
tools.replace_in_file(cmakelists_src, "${ZLIB_LIBRARIES}", "ZLIB::ZLIB")
if not self.options.with_zlib:
tools.replace_in_file(cmakelists_src, "if (ZLIB_LIBRARIES)", "if(0)")
tools.replace_in_file(cmake_configure, "if (ZLIB_FOUND)", "if(0)")
## giflib
tools.replace_in_file(cmakelists_src, "${GIF_LIBRARIES}", "GIF::GIF")
if not self.options.with_gif:
tools.replace_in_file(cmakelists_src, "if (GIF_LIBRARIES)", "if(0)")
tools.replace_in_file(cmake_configure, "if (GIF_FOUND)", "if(0)")
## libjpeg
tools.replace_in_file(cmakelists_src, "${JPEG_LIBRARIES}", "JPEG::JPEG")
if not self.options.with_jpeg:
tools.replace_in_file(cmakelists_src, "if (JPEG_LIBRARIES)", "if(0)")
tools.replace_in_file(cmake_configure, "if (JPEG_FOUND)", "if(0)")
## libpng
tools.replace_in_file(cmakelists_src, "${PNG_LIBRARIES}", "PNG::PNG")
if not self.options.with_png:
tools.replace_in_file(cmakelists_src, "if (PNG_LIBRARIES)", "if(0)")
tools.replace_in_file(cmake_configure, "if (PNG_FOUND)", "if(0)")
## libtiff
tools.replace_in_file(cmakelists_src, "${TIFF_LIBRARIES}", "TIFF::TIFF")
if not self.options.with_tiff:
tools.replace_in_file(cmakelists_src, "if (TIFF_LIBRARIES)", "if(0)")
tools.replace_in_file(cmake_configure, "if (TIFF_FOUND)", "if(0)")
## We have to be more aggressive with dependencies found with pkgconfig
## Injection of libdirs is ensured by conan_basic_setup()
## openjpeg
tools.replace_in_file(cmakelists, "if(NOT JP2K)", "if(0)")
tools.replace_in_file(cmakelists_src,
"if (JP2K_FOUND)",
"if (JP2K_FOUND)\n"
"target_compile_definitions(leptonica PRIVATE ${JP2K_CFLAGS_OTHER})")
if not self.options.with_openjpeg:
tools.replace_in_file(cmake_original,
"if(NOT JP2K)",
"if(FALSE)")
tools.replace_in_file(cmakelists_src, "if (JP2K_FOUND)", "if(0)")
tools.replace_in_file(cmake_configure, "if (JP2K_FOUND)", "if(0)")
## libwebp
tools.replace_in_file(cmakelists, "if(NOT WEBP)", "if(0)")
tools.replace_in_file(cmakelists_src,
"if (WEBP_FOUND)",
"if (WEBP_FOUND)\n"
"target_compile_definitions(leptonica PRIVATE ${WEBP_CFLAGS_OTHER} ${WEBPMUX_CFLAGS_OTHER})")
tools.replace_in_file(cmakelists_src, "${WEBP_LIBRARIES}", "${WEBP_LIBRARIES} ${WEBPMUX_LIBRARIES}")
if tools.Version(self.version) >= "1.79.0":
tools.replace_in_file(cmakelists, "if(NOT WEBPMUX)", "if(0)")
if not self.options.with_webp:
tools.replace_in_file(cmakelists_src, "if (WEBP_FOUND)", "if(0)")
tools.replace_in_file(cmake_configure, "if (WEBP_FOUND)", "if(0)")

# Remove detection of fmemopen() on macOS < 10.13
# CheckFunctionExists will find it in the link library.
# There's no error because it's not including the header with the
# deprecation macros.
if self.settings.os == 'Macos' and self.settings.os.version:
if tools.Version(self.settings.os.version) < '10.13':
configure_cmake = os.path.join(self._source_subfolder,
'cmake',
'Configure.cmake')
tools.replace_in_file(configure_cmake,
'set(functions_list\n '
'fmemopen\n fstatat\n)',
'set(functions_list\n '
'fstatat\n)')

# upstream uses obsolete FOO_LIBRARY that is not generated
# by cmake_find_package generator (upstream PR 456)
if tools.Version(self.version) <= '1.78.0':
for dep in ('GIF', 'TIFF', 'PNG', 'JPEG', 'ZLIB'):
tools.replace_in_file(os.path.join(self._source_subfolder, "src", "CMakeLists.txt"),
dep + "_LIBRARY",
dep + "_LIBRARIES")
if self.settings.os == "Macos" and self.settings.os.version:
if tools.Version(self.settings.os.version) < "10.13":
tools.replace_in_file(cmake_configure,
"set(functions_list\n "
"fmemopen\n fstatat\n)",
"set(functions_list\n "
"fstatat\n)")

def _configure_cmake(self):
if self._cmake:
return self._cmake
self._cmake = CMake(self)
if tools.Version(self.version) < "1.79.0":
self._cmake.definitions["STATIC"] = not self.options.shared
self._cmake.definitions["BUILD_PROG"] = False
self._cmake.definitions["SW_BUILD"] = False
self._cmake.configure(build_folder=self._build_subfolder)
return self._cmake

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

def package(self):
cmake = self._configure_cmake()
cmake.install()

self.copy(pattern="leptonica-license.txt", dst="licenses", src=self._source_subfolder)
# remove pkgconfig
tools.rmdir(os.path.join(self.package_folder, 'lib', 'pkgconfig'))
# remove cmake
tools.rmdir(os.path.join(self.package_folder, 'cmake'))
tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))
tools.rmdir(os.path.join(self.package_folder, "cmake"))
self._create_cmake_module_alias_targets(
os.path.join(self.package_folder, self._module_file_rel_path),
{"leptonica": "Leptonica::Leptonica"}
)

@staticmethod
def _create_cmake_module_alias_targets(module_file, targets):
content = ""
for alias, aliased in targets.items():
content += textwrap.dedent("""\
if(TARGET {aliased} AND NOT TARGET {alias})
add_library({alias} INTERFACE IMPORTED)
set_property(TARGET {alias} PROPERTY INTERFACE_LINK_LIBRARIES {aliased})
endif()
""".format(alias=alias, aliased=aliased))
tools.save(module_file, content)

@property
def _module_subfolder(self):
return os.path.join("lib", "cmake")

@property
def _module_file_rel_path(self):
return os.path.join(self._module_subfolder,
"conan-official-{}-targets.cmake".format(self.name))

def package_info(self):
self.cpp_info.libs = tools.collect_libs(self)
if self.settings.os == "Linux":
self.cpp_info.system_libs = ["m"]
self.cpp_info.names["cmake_find_package"] = "Leptonica"
self.cpp_info.names["cmake_find_package_multi"] = "Leptonica"
self.cpp_info.names['pkg_config'] = 'lept'
self.cpp_info.builddirs.append(self._module_subfolder)
self.cpp_info.build_modules["cmake_find_package"] = [self._module_file_rel_path]
self.cpp_info.build_modules["cmake_find_package_multi"] = [self._module_file_rel_path]
self.cpp_info.names["pkg_config"] = "lept"
self.cpp_info.includedirs.append(os.path.join("include", "leptonica"))
48 changes: 48 additions & 0 deletions recipes/leptonica/all/patches/fix-find-modules-variables.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
see https://github.com/DanBloomberg/leptonica/pull/456

--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -31,33 +31,33 @@ if (NOT STATIC)
target_compile_definitions (leptonica PRIVATE -DLIBLEPT_EXPORTS)
endif()

-if (GIF_LIBRARY)
+if (GIF_LIBRARIES)
target_include_directories (leptonica PUBLIC ${GIF_INCLUDE_DIR})
- target_link_libraries (leptonica ${GIF_LIBRARY})
+ target_link_libraries (leptonica ${GIF_LIBRARIES})
endif()
-if (JPEG_LIBRARY)
+if (JPEG_LIBRARIES)
target_include_directories (leptonica PUBLIC ${JPEG_INCLUDE_DIR})
- target_link_libraries (leptonica ${JPEG_LIBRARY})
+ target_link_libraries (leptonica ${JPEG_LIBRARIES})
endif()
if (JP2K_FOUND)
target_include_directories (leptonica PUBLIC ${JP2K_INCLUDE_DIRS})
target_link_libraries (leptonica ${JP2K_LIBRARIES})
endif()
-if (PNG_LIBRARY)
+if (PNG_LIBRARIES)
target_include_directories (leptonica PUBLIC ${PNG_INCLUDE_DIRS})
- target_link_libraries (leptonica ${PNG_LIBRARY})
+ target_link_libraries (leptonica ${PNG_LIBRARIES})
endif()
-if (TIFF_LIBRARY)
+if (TIFF_LIBRARIES)
target_include_directories (leptonica PUBLIC ${TIFF_INCLUDE_DIR})
- target_link_libraries (leptonica ${TIFF_LIBRARY})
+ target_link_libraries (leptonica ${TIFF_LIBRARIES})
endif()
if (WEBP_FOUND)
target_include_directories (leptonica PUBLIC ${WEBP_INCLUDE_DIRS})
target_link_libraries (leptonica ${WEBP_LIBRARIES})
endif()
-if (ZLIB_LIBRARY)
+if (ZLIB_LIBRARIES)
target_include_directories (leptonica PUBLIC ${ZLIB_INCLUDE_DIR})
- target_link_libraries (leptonica ${ZLIB_LIBRARY})
+ target_link_libraries (leptonica ${ZLIB_LIBRARIES})
endif()

if (UNIX)
10 changes: 6 additions & 4 deletions recipes/leptonica/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
cmake_minimum_required(VERSION 3.1)
project(test_package)
project(test_package C)

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

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
find_package(Leptonica REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.c)
target_link_libraries(${PROJECT_NAME} leptonica)

0 comments on commit 3ee8a20

Please sign in to comment.