Skip to content

Commit

Permalink
(#13113) qpdf/11.1.1 add (lib only) package
Browse files Browse the repository at this point in the history
* initial conan qpdf package implementation

* make conan check hooks green: missing new line on test_package.cpp

* add current cmake as build_requirements

* remove comments as requested from review

* remove validation check from example, which was not validated for the current pacakge

* remove implicit library depdendency from example

* remove further comments from example

* simplify test_package to just print QPDF_VERSION

* provide crypto provider selection

* reenable missing system lib dependency m

* cope with minor linting warnings

* add gnutls option as a placeholder, to activate later on but not change package-id

* remove further comments

* remove not matching cleanup for packaging

* add minimal as possible pdf handling to test_package to ensure link-time dependency check

* cope with unused lint warning

* introduce jpeg dependency option

* add conan v1 test

* fix up test_v1_package for shared builds: correct the build env passing to v1

* convert line breaks

* fix the visual code version number to select full C++14 supported compilers

* try to migrate to is_msvc instead of own version comparison for vs compiler

* remove duplicated test package source file

* clean import statement

* go for string based compiler version comparison

* call binaries of the package directly without manual path determination to ensure they are exisiting in PATH

* provide pkgconf as explicit build dependency, since msvc has it not preinstalled and the others are only green because of implicit shipment in ci env

* revert import review change, since it triggers the linter

* patch level update qpdf to 11.1.1

* fix missing version update entry in config.yml

* try to fix linter on import statement

* add packageConfigDeps and virtual build env to toolchain configure handling

* current workaround for missing pkg_config dependency retrieval from cmake qpdf project: set PKG_CONFIG_PATH manually

* switch to working openssl version as qpdf dependency

* switch to libqpdf build only; patch qpdf cmake build files, injecting conans CMakeDeps

* cope with linter warning

* remove not anymore compiled binaries from test_v1

* apply review changes

* disable mac shared builds

* try to get around windows and mac shared lib missing symbols into libjpeg, potentially caused by private linkage of libjpeg

* try to fix missing libjpeg symols problem for shared libs on windows according to review

* provide cmake dependencies also to shared and static lib target directly and not only to the object lib

* try to reenable mac os, since the missing symbols should be caused on windows and mac for same reason

* reuse existing target_link_libraries calls and append conan libs to them instead of calling it multiple times

* add missing public entries to target_link_libraries

* move cmake deps out of atomic library check and set only once for every library type

* remove wrongly reintroduces target_link_libraries from overwritten qpdf deps

* try to fix msvc tests with code-path avoiding #warning macro

* cope with linter error

* add necessary compile-definition also to test_v1_package

* cope with linter error

* Update recipes/qpdf/all/conanfile.py

Co-authored-by: Jordan Williams <jordan@jwillikers.com>

* Update recipes/qpdf/all/test_package/CMakeLists.txt

Co-authored-by: Jordan Williams <jordan@jwillikers.com>

* Update recipes/qpdf/all/test_v1_package/CMakeLists.txt

Co-authored-by: Jordan Williams <jordan@jwillikers.com>

* Update recipes/qpdf/all/conanfile.py

Co-authored-by: Jordan Williams <jordan@jwillikers.com>

* Update recipes/qpdf/all/test_v1_package/CMakeLists.txt

Co-authored-by: Jordan Williams <jordan@jwillikers.com>

* make it link correctly again

* remove not anymore necessary way to provide conan dependencies via pkg_config, since we patch CMakeDeps already in the qpdf build

* Update recipes/qpdf/all/conanfile.py

Co-authored-by: Jordan Williams <jordan@jwillikers.com>

* Update recipes/qpdf/all/conanfile.py

Co-authored-by: Jordan Williams <jordan@jwillikers.com>

* fix python function name definition

* avoid cmake SEND_ERROR and FATAL_ERROR on patched-away dependency handling

* fix patch base addresses

* Update recipes/qpdf/all/conandata.yml

Co-authored-by: Chris Mc <prince.chrismc@gmail.com>

* Update recipes/qpdf/all/conanfile.py

Co-authored-by: Chris Mc <prince.chrismc@gmail.com>

* export example file with fixed path from binary instead of agrument from test_package/conanfile.py

* clarify options names: with_crypto -> with_ssl; native -> internal

* avoid code-duplication in patch-files, go for conditional python patching of already patched file instead

* review-changes: add description and type for patches

* follow more precise the documentation guideline

* prepare gnutls config

* deactivate special windows exernal lib handling

* Patch found crypto flags, corresponding to conan options. This should finally fix windows plattform of not enabling openssl sources, even when conan does provide openssl.

* update dependencies

* remove slightly misleading comment

Co-authored-by: Jordan Williams <jordan@jwillikers.com>
Co-authored-by: Chris Mc <prince.chrismc@gmail.com>
  • Loading branch information
3 people authored Oct 17, 2022
1 parent 126c82e commit 936eef0
Show file tree
Hide file tree
Showing 10 changed files with 417 additions and 0 deletions.
12 changes: 12 additions & 0 deletions recipes/qpdf/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sources:
"11.1.1":
url: "https://github.com/qpdf/qpdf/archive/refs/tags/v11.1.1.tar.gz"
sha256: "785edab622a1bc7e25e1537ad2c325005d48c5c7957f7abedff405deb80fa59a"
patches:
"11.1.1":
- patch_file: "patches/0001-libqpdf-cmake-deps-jpeg-zlib.patch"
patch_description: "Inject Conan Deps, disable qpdf-dep handling: update libqpdf/CMakeLists.txt by disabling cmake fails, caused by pkg_config fail to find dependencies. Add conan generated cmake dependencies instead."
patch_type: "conan"
- patch_file: "patches/0002-exclude-unnecessary-cmake-subprojects.patch"
patch_description: "Exclude unnecessary targets: update CMakeLists.txt removing subdir includes for binaries, tests, examples, docs and fuzzing"
patch_type: "conan"
181 changes: 181 additions & 0 deletions recipes/qpdf/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.build import check_min_cppstd
from conan.tools.scm import Version
from conan.tools.files import replace_in_file, apply_conandata_patches, export_conandata_patches, get, copy, rmdir
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.microsoft import is_msvc, check_min_vs
from conan.tools.env import VirtualBuildEnv
import os

required_conan_version = ">=1.52.0"

class PackageConan(ConanFile):
name = "qpdf"
description = "QPDF is a command-line tool and C++ library that performs content-preserving transformations on PDF files."
license = "Apache-2.0"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/qpdf/qpdf"
topics = ("pdf")
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"with_ssl": ["internal", "openssl", "gnutls"],
"with_jpeg": ["libjpeg", "libjpeg-turbo", "mozjpeg"],
}
default_options = {
"shared": False,
"fPIC": True,
"with_ssl": "openssl",
"with_jpeg": "libjpeg",
}

@property
def _minimum_cpp_standard(self):
return 14

@property
def _compilers_minimum_version(self):
return {
"gcc": "5",
"clang": "3.4",
"apple-clang": "10",
}

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:
try:
del self.options.fPIC
except Exception:
pass

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

def requirements(self):
# https://qpdf.readthedocs.io/en/stable/installation.html#basic-dependencies
self.requires("zlib/1.2.13")
if self.options.with_ssl == "openssl":
self.requires("openssl/1.1.1q")
elif self.options.with_ssl == "gnutls":
raise ConanInvalidConfiguration("GnuTLS is not available in Conan Center yet.")
if self.options.with_jpeg == "libjpeg":
self.requires("libjpeg/9e")
elif self.options.with_jpeg == "libjpeg-turbo":
self.requires("libjpeg-turbo/2.1.4")
elif self.options.with_jpeg == "mozjpeg":
self.requires("mozjpeg/4.1.1")


def validate(self):
if self.info.settings.compiler.cppstd:
check_min_cppstd(self, self._minimum_cpp_standard)
if is_msvc(self):
check_min_vs(self, "150")
else:
minimum_version = self._compilers_minimum_version.get(str(self.info.settings.compiler), False)
if minimum_version and Version(self.info.settings.compiler.version) < minimum_version:
raise ConanInvalidConfiguration(f"{self.ref} requires C++{self._minimum_cpp_standard}, which your compiler does not support.")

def build_requirements(self):
self.tool_requires("cmake/3.24.1")
self.tool_requires("pkgconf/1.9.3")

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

def generate(self):
tc = CMakeToolchain(self)
tc.variables["BUILD_STATIC_LIBS"] = not self.options.shared
# https://qpdf.readthedocs.io/en/latest/installation.html#build-time-crypto-selection
tc.variables["USE_IMPLICIT_CRYPTO"] = False
tc.cache_variables["CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP"] = True
if self.options.with_ssl == "internal":
tc.variables["REQUIRE_CRYPTO_NATIVE"] = True
tc.variables["REQUIRE_CRYPTO_GNUTLS"] = False
tc.variables["REQUIRE_CRYPTO_OPENSSL"] = False
if self.options.with_ssl == "openssl":
tc.variables["REQUIRE_CRYPTO_NATIVE"] = False
tc.variables["REQUIRE_CRYPTO_GNUTLS"] = False
tc.variables["REQUIRE_CRYPTO_OPENSSL"] = True
if self.options.with_ssl == "gnutls":
tc.variables["REQUIRE_CRYPTO_NATIVE"] = False
tc.variables["REQUIRE_CRYPTO_GNUTLS"] = True
tc.variables["REQUIRE_CRYPTO_OPENSSL"] = False
tc.generate()
# TODO: after https://github.com/conan-io/conan/issues/11962 is solved
# we might obsolete here cmake deps generation and cmake patching and get
# the possibility to go for to pkg_config based dependency discovery instead.
# At the moment, even with the linked work-around, the linkage is mixed-up
tc = CMakeDeps(self)
tc.generate()
tc = VirtualBuildEnv(self)
tc.generate(scope="build")

def _patch_sources(self):
apply_conandata_patches(self)
# we generally expect to have one crypto in-place, but need to patch the found mechanics
# since we avoid currently the correct pkg_config
replace_in_file(self, os.path.join(self.source_folder, "libqpdf", "CMakeLists.txt"),
"set(FOUND_CRYPTO OFF)", "set(FOUND_CRYPTO ON)")
if self.options.with_ssl == "openssl":
replace_in_file(self, os.path.join(self.source_folder, "libqpdf", "CMakeLists.txt"),
"set(USE_CRYPTO_OPENSSL OFF)", "set(USE_CRYPTO_OPENSSL ON)")
replace_in_file(self, os.path.join(self.source_folder, "libqpdf", "CMakeLists.txt"),
"find_package(ZLIB REQUIRED)",
"find_package(ZLIB REQUIRED)\nfind_package(OpenSSL REQUIRED)\n")
replace_in_file(self, os.path.join(self.source_folder, "libqpdf", "CMakeLists.txt"),
"PUBLIC JPEG::JPEG ZLIB::ZLIB", "PUBLIC JPEG::JPEG ZLIB::ZLIB OpenSSL::SSL")
if self.options.with_ssl == "gnutls":
replace_in_file(self, os.path.join(self.source_folder, "libqpdf", "CMakeLists.txt"),
"set(USE_CRYPTO_GNUTLS OFF)", "set(USE_CRYPTO_GNUTLS ON)")
if self.options.with_ssl == "internal":
replace_in_file(self, os.path.join(self.source_folder, "libqpdf", "CMakeLists.txt"),
"set(USE_CRYPTO_NATIVE OFF)", "set(USE_CRYPTO_NATIVE ON)")

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

def package(self):
copy(self, pattern="LICENSE.txt", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder)
cmake = CMake(self)
cmake.install()

rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
rmdir(self, os.path.join(self.package_folder, "share"))

def package_info(self):
self.cpp_info.set_property("cmake_file_name", "qpdf")

self.cpp_info.components["libqpdf"].libs = ["qpdf"]
self.cpp_info.components["libqpdf"].set_property("pkg_config_name", "libqpdf")
self.cpp_info.components["libqpdf"].set_property("cmake_target_name", "qpdf::libqpdf")
self.cpp_info.components["libqpdf"].requires.append("zlib::zlib")
self.cpp_info.components["libqpdf"].requires.append(f"{self.options.with_jpeg}::{self.options.with_jpeg}")

if self.options.with_ssl == "openssl":
self.cpp_info.components["libqpdf"].requires.append("openssl::openssl")

if self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.components["libqpdf"].system_libs.append("m")

# TODO: to remove in conan v2 once cmake_find_package_* generators removed
self.cpp_info.filenames["cmake_find_package"] = "qpdf"
self.cpp_info.filenames["cmake_find_package_multi"] = "qpdf"
self.cpp_info.names["cmake_find_package"] = "qpdf"
self.cpp_info.names["cmake_find_package_multi"] = "qpdf"
self.cpp_info.components["libqpdf"].names["cmake_find_package"] = "libqpdf"
self.cpp_info.components["libqpdf"].names["cmake_find_package_multi"] = "libqpdf"
113 changes: 113 additions & 0 deletions recipes/qpdf/all/patches/0001-libqpdf-cmake-deps-jpeg-zlib.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt
index 7053e205..9f5962f7 100644
--- a/libqpdf/CMakeLists.txt
+++ b/libqpdf/CMakeLists.txt
@@ -128,13 +128,8 @@ include(CheckSymbolExists)
set(dep_include_directories)
set(dep_link_directories)
set(dep_link_libraries)
-set(ANYTHING_MISSING 0)

-if(WIN32 AND (EXISTS ${qpdf_SOURCE_DIR}/external-libs))
- set(EXTERNAL_LIBS 1)
-else()
- set(EXTERNAL_LIBS 0)
-endif()
+set(EXTERNAL_LIBS 0)

if(EXTERNAL_LIBS)
set(EXTLIBDIR ${qpdf_SOURCE_DIR}/external-libs)
@@ -161,9 +156,6 @@ if(NOT EXTERNAL_LIBS)
if(ZLIB_H_PATH AND ZLIB_LIB_PATH)
list(APPEND dep_include_directories ${ZLIB_H_PATH})
list(APPEND dep_link_libraries ${ZLIB_LIB_PATH})
- else()
- message(SEND_ERROR "zlib not found")
- set(ANYTHING_MISSING 1)
endif()
endif()
endif()
@@ -182,9 +174,6 @@ if(NOT EXTERNAL_LIBS)
list(APPEND dep_include_directories ${LIBJPEG_H_PATH})
list(APPEND dep_link_libraries ${LIBJPEG_LIB_PATH})
set(JPEG_INCLUDE ${LIBJPEG_H_PATH})
- else()
- message(SEND_ERROR "libjpeg not found")
- set(ANYTHING_MISSING 1)
endif()
endif()
endif()
@@ -220,9 +209,6 @@ if(USE_IMPLICIT_CRYPTO OR REQUIRE_CRYPTO_OPENSSL)
list(APPEND dep_link_libraries ${OPENSSL_LIB_PATH})
set(USE_CRYPTO_OPENSSL ON)
set(FOUND_CRYPTO ON)
- elseif(REQUIRE_CRYPTO_OPENSSL)
- message(SEND_ERROR "openssl not found")
- set(ANYTHING_MISSING 1)
endif()
endif()
endif()
@@ -241,9 +227,6 @@ if(USE_IMPLICIT_CRYPTO OR REQUIRE_CRYPTO_GNUTLS)
list(APPEND dep_link_libraries ${GNUTLS_LIB_PATH})
set(USE_CRYPTO_GNUTLS ON)
set(FOUND_CRYPTO ON)
- elseif(REQUIRE_CRYPTO_GNUTLS)
- message(SEND_ERROR "gnutls not found")
- set(ANYTHING_MISSING 1)
endif()
endif()
endif()
@@ -268,14 +251,9 @@ if(FOUND_CRYPTO)
set(DEFAULT_CRYPTO "native")
endif()
endif()
-else()
- message(SEND_ERROR "no crypto provider is available")
- set(ANYTHING_MISSING 1)
-endif()
-if(ANYTHING_MISSING)
- message(FATAL_ERROR "Missing dependencies; unable to continue")
endif()

+
message(STATUS "")
message(STATUS "*** Crypto Summary ***")
message(STATUS " GNU TLS crypto enabled: " ${USE_CRYPTO_GNUTLS})
@@ -403,6 +381,10 @@ endif()
# use PIC for the object library so we don't have to compile twice.
set(OBJECT_LIB libqpdf_object)
add_library(${OBJECT_LIB} OBJECT ${libqpdf_SOURCES})
+find_package(JPEG REQUIRED)
+find_package(ZLIB REQUIRED)
+target_link_libraries(${OBJECT_LIB} PUBLIC JPEG::JPEG ZLIB::ZLIB)
+
if(OBJECT_LIB_IS_PIC)
target_compile_definitions(${OBJECT_LIB} PRIVATE libqpdf_EXPORTS)
endif()
@@ -498,8 +480,6 @@ if(BUILD_SHARED_LIBS)
PUBLIC
$<BUILD_INTERFACE:${qpdf_INCLUDE}>
$<INSTALL_INTERFACE:include>)
- target_link_directories(${SHARED_LIB} PRIVATE ${dep_link_directories})
- target_link_libraries(${SHARED_LIB} PRIVATE ${dep_link_libraries})
if(ATOMIC_LIBRARY)
target_link_libraries(${SHARED_LIB} PRIVATE ${ATOMIC_LIBRARY})
endif()
@@ -507,6 +487,8 @@ if(BUILD_SHARED_LIBS)
target_link_options(${SHARED_LIB} PRIVATE ${LD_VERSION_FLAGS})
endif()

+ target_link_libraries(${SHARED_LIB} PUBLIC JPEG::JPEG ZLIB::ZLIB)
+
target_include_directories(${SHARED_LIB}
PRIVATE ${qpdf_SOURCE_DIR}/libqpdf ${CMAKE_CURRENT_BINARY_DIR})

@@ -544,6 +526,8 @@ if(BUILD_STATIC_LIBS)
target_link_libraries(${STATIC_LIB} INTERFACE ${ATOMIC_LIBRARY})
endif()

+ target_link_libraries(${STATIC_LIB} PUBLIC JPEG::JPEG ZLIB::ZLIB)
+
# Avoid name clashes on Windows with the the DLL import library.
if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS)
if (WIN32)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5c0915f3..6c4945d3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -323,12 +323,6 @@ add_test(
# add_subdirectory order affects test order
add_subdirectory(include)
add_subdirectory(libqpdf)
-add_subdirectory(qpdf)
-add_subdirectory(libtests)
-add_subdirectory(examples)
-add_subdirectory(zlib-flate)
-add_subdirectory(manual)
-add_subdirectory(fuzz)

# We don't need to show everything -- just the things that we really
# need to be sure are right or that are turned on or off with complex
12 changes: 12 additions & 0 deletions recipes/qpdf/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.8)

project(test_package CXX)

find_package(qpdf REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE qpdf::libqpdf)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14)
# msvc has problems consuming #warning macro
# therefore we need a code-path in the include avoiding this warning https://github.com/qpdf/qpdf/issues/804
target_compile_definitions(${PROJECT_NAME} PUBLIC POINTERHOLDER_TRANSITION=4)
24 changes: 24 additions & 0 deletions recipes/qpdf/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import cmake_layout, CMake
import os

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

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

def layout(self):
cmake_layout(self)

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

def test(self):
if can_run(self):
self.run(os.path.join(self.cpp.build.bindirs[0], "test_package"), env="conanrun")
21 changes: 21 additions & 0 deletions recipes/qpdf/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <qpdf/DLL.h>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFWriter.hh>
#include <iostream>

int main(int argc, char* argv[])
{
std::cout << "QPDF_VERSION " << QPDF_VERSION << "\n";

try {
QPDF pdf;
pdf.emptyPDF();
QPDFWriter w(pdf, "empty_example.pdf");
w.write();
} catch (std::exception& e) {
std::cerr << e.what() << "\n";
exit(2);
}

return 0;
}
Loading

0 comments on commit 936eef0

Please sign in to comment.