Skip to content

Commit

Permalink
[CMakeToolchain][env] Added PKG_CONFIG_PATH env variable and PKG_CONF…
Browse files Browse the repository at this point in the history
…IG_EXECUTABLE one (#12513)

* handle conf `tools.gnu:pkg_config` in `CMakeToolchain`

* return a mapping

* not default=False in self.conf.get

Co-authored-by: James <james@conan.io>

* Added integration test

* Added PKG_CONFIG_PATH automatically to CMakeToolchain

* Changed proposal

* Applied suggestions

* renamed test var

* Safer pathsep based on settings and sanitize path

* fixing tests

* Deducing subsytem

Co-authored-by: SpaceIm <30052553+SpaceIm@users.noreply.github.com>
Co-authored-by: James <james@conan.io>
  • Loading branch information
3 people authored Nov 16, 2022
1 parent 857c3d1 commit 559bca1
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 8 deletions.
31 changes: 30 additions & 1 deletion conan/tools/cmake/toolchain/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from conan.tools.cmake.toolchain import CONAN_TOOLCHAIN_FILENAME
from conan.tools.intel import IntelCC
from conan.tools.microsoft.visual import is_msvc, msvc_version_to_toolset_version
from conans.client.subsystems import deduce_subsystem, WINDOWS
from conans.errors import ConanException
from conans.util.files import load

Expand Down Expand Up @@ -153,7 +154,7 @@ class FPicBlock(Block):
template = textwrap.dedent("""
{% if fpic %}
message(STATUS "Conan toolchain: Setting CMAKE_POSITION_INDEPENDENT_CODE={{ fpic }} (options.fPIC)")
set(CMAKE_POSITION_INDEPENDENT_CODE {{ fpic }} CACHE BOOL "Position independent code")
set(CMAKE_POSITION_INDEPENDENT_CODE {{ fpic }} CACHE BOOL "Position independent code")
{% endif %}
""")

Expand Down Expand Up @@ -559,6 +560,34 @@ def context(self):
}


class PkgConfigBlock(Block):
template = textwrap.dedent("""
{% if pkg_config %}
set(PKG_CONFIG_EXECUTABLE {{ pkg_config }} CACHE FILEPATH "pkg-config executable")
{% endif %}
{% if pkg_config_path %}
if (DEFINED ENV{PKG_CONFIG_PATH})
set(ENV{PKG_CONFIG_PATH} "{{ pkg_config_path }}$ENV{PKG_CONFIG_PATH}")
else()
set(ENV{PKG_CONFIG_PATH} "{{ pkg_config_path }}")
endif()
{% endif %}
""")

def context(self):
pkg_config = self._conanfile.conf.get("tools.gnu:pkg_config", check_type=str)
if pkg_config:
pkg_config = pkg_config.replace("\\", "/")
pkg_config_path = self._conanfile.generators_folder
if pkg_config_path:
# hardcoding scope as "build"
subsystem = deduce_subsystem(self._conanfile, "build")
pathsep = ":" if subsystem != WINDOWS else ";"
pkg_config_path = pkg_config_path.replace("\\", "/") + pathsep
return {"pkg_config": pkg_config,
"pkg_config_path": pkg_config_path}


class UserToolchain(Block):
template = textwrap.dedent("""
{% for user_toolchain in paths %}
Expand Down
5 changes: 3 additions & 2 deletions conan/tools/cmake/toolchain/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from conan.tools.cmake.toolchain import CONAN_TOOLCHAIN_FILENAME
from conan.tools.cmake.toolchain.blocks import ToolchainBlocks, UserToolchain, GenericSystemBlock, \
AndroidSystemBlock, AppleSystemBlock, FPicBlock, ArchitectureBlock, GLibCXXBlock, VSRuntimeBlock, \
CppStdBlock, ParallelBlock, CMakeFlagsInitBlock, TryCompileBlock, FindFiles, SkipRPath, \
SharedLibBock, OutputDirsBlock, ExtraFlagsBlock
CppStdBlock, ParallelBlock, CMakeFlagsInitBlock, TryCompileBlock, FindFiles, PkgConfigBlock, \
SkipRPath, SharedLibBock, OutputDirsBlock, ExtraFlagsBlock
from conan.tools.intel import IntelCC
from conan.tools.microsoft import VCVars
from conan.tools.microsoft.visual import vs_ide_version
Expand Down Expand Up @@ -139,6 +139,7 @@ def __init__(self, conanfile, generator=None):
("cmake_flags_init", CMakeFlagsInitBlock),
("try_compile", TryCompileBlock),
("find_paths", FindFiles),
("pkg_config", PkgConfigBlock),
("rpath", SkipRPath),
("shared", SharedLibBock),
("output_dirs", OutputDirsBlock)])
Expand Down
66 changes: 61 additions & 5 deletions conans/test/functional/toolchains/cmake/test_cmake_toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@ def test_cmake_toolchain_vars_when_option_declared():

t.run("new mylib/1.0 --template cmake_lib")
t.save({"CMakeLists.txt": cmakelists})

# The generated toolchain should set `BUILD_SHARED_LIBS` to `OFF`,
# and `CMAKE_POSITION_INDEPENDENT_CODE` to `ON` and the calls to
# `option()` in the CMakeLists.txt should respect the existing values.
Expand All @@ -1112,7 +1112,7 @@ def test_cmake_toolchain_vars_when_option_declared():
assert "mylib target type: STATIC_LIBRARY" in t.out
assert f"mylib position independent code: {fpic_cmake_value}" in t.out

# When building manually, ensure the value passed by the toolchain overrides the ones in
# When building manually, ensure the value passed by the toolchain overrides the ones in
# the CMakeLists
fpic_option = "-o mylib:fPIC=False" if platform.system() != "Windows" else ""
t.run(f"install . -o mylib:shared=False {fpic_option}")
Expand Down Expand Up @@ -1198,10 +1198,10 @@ class PkgConan(ConanFile):
def layout(self):
cmake_layout(self)
def requirements(self):
self.requires("foobar/1.0")
def build_requirements(self):
self.tool_requires("foobar/1.0")
""")
Expand All @@ -1227,7 +1227,63 @@ def build_requirements(self):

with client.chdir("build"):
client.run_command("cmake .. -DCMAKE_TOOLCHAIN_FILE=generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release")
# Verify binary executable is found from build context package,
# Verify binary executable is found from build context package,
# and library comes from host context package
assert f"package/{build_context_package_id}/bin/foobin" in client.out
assert f"package/{host_context_package_id}/include" in client.out


@pytest.mark.tool_pkg_config
def test_cmaketoolchain_and_pkg_config_path():
"""
Lightweight test which is loading a dependency as a *.pc file through
CMake thanks to pkg_check_modules macro.
It's working because PKG_CONFIG_PATH env variable is being loaded automatically
by the CMakeToolchain generator.
"""
client = TestClient()
dep = textwrap.dedent("""
from conan import ConanFile
class DepConan(ConanFile):
name = "dep"
version = "1.0"
def package_info(self):
self.cpp_info.libs = ["dep"]
""")
pkg = textwrap.dedent("""
from conan import ConanFile
from conan.tools.cmake import CMake, cmake_layout
class HelloConan(ConanFile):
name = "pkg"
version = "1.0"
settings = "os", "compiler", "build_type", "arch"
generators = "PkgConfigDeps", "CMakeToolchain"
exports_sources = "CMakeLists.txt"
def requirements(self):
self.requires("dep/1.0")
def layout(self):
cmake_layout(self)
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
""")
cmakelists = textwrap.dedent("""
cmake_minimum_required(VERSION 3.15)
project(pkg CXX)
find_package(PkgConfig REQUIRED)
# We should have PKG_CONFIG_PATH created in the current environment
pkg_check_modules(DEP REQUIRED IMPORTED_TARGET dep)
""")
client.save({
"dep/conanfile.py": dep,
"pkg/conanfile.py": pkg,
"pkg/CMakeLists.txt": cmakelists
})
client.run("create dep/conanfile.py")
client.run("create pkg/conanfile.py")
assert "Found dep, version 1.0" in client.out
26 changes: 26 additions & 0 deletions conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,3 +758,29 @@ def layout(self):
presets = json.loads(client.load("build/14/generators/CMakePresets.json"))
assert "architecture" in presets["configurePresets"][0]
assert "toolset" not in presets["configurePresets"][0]


def test_pkg_config_block():
os_ = platform.system()
os_ = "Macos" if os_ == "Darwin" else os_
profile = textwrap.dedent("""
[settings]
os=%s
arch=x86_64
[conf]
tools.gnu:pkg_config=/usr/local/bin/pkg-config
""" % os_)

client = TestClient(path_with_spaces=False)
conanfile = GenConanfile().with_settings("os", "arch")\
.with_generator("CMakeToolchain")
client.save({"conanfile.py": conanfile,
"profile": profile})
client.run("install . -pr:b profile -pr:h profile")
toolchain = client.load("conan_toolchain.cmake")
assert 'set(PKG_CONFIG_EXECUTABLE /usr/local/bin/pkg-config CACHE FILEPATH ' in toolchain
pathsep = ":" if os_ != "Windows" else ";"
pkg_config_path_set = 'set(ENV{PKG_CONFIG_PATH} "%s$ENV{PKG_CONFIG_PATH}")' % \
(client.current_folder.replace("\\", "/") + pathsep)
assert pkg_config_path_set in toolchain

0 comments on commit 559bca1

Please sign in to comment.