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

Avoid public reach of transitory dependency #43251

Open
NahuFigueroa97 opened this issue Jan 14, 2025 · 17 comments
Open

Avoid public reach of transitory dependency #43251

NahuFigueroa97 opened this issue Jan 14, 2025 · 17 comments
Assignees
Labels
category:vcpkg-feature The issue is a new capability of the tool that doesn’t already exist and we haven’t committed

Comments

@NahuFigueroa97
Copy link

Continuing with the problem #24558 I wanted to ask why the transient dependencies remain as public throughout the project. I use curl which has openssl installed. This causes that even if I do not link the library in the cmake of the project the transient dependency is found. How can I solve this? I would like to know if there is a way for all the executables to use the openssl that I configured in my vcpkg.json and not the transient dependency since it contaminates my environment.

@autoantwort
Copy link
Contributor

why the transient dependencies remain as public throughout the project

What do you mean?

I would like to know if there is a way for all the executables to use the openssl that I configured in my vcpkg.json and not the transient dependency

You mean the openssl from vcpkg vs the openssl from the system?

@NahuFigueroa97
Copy link
Author

NahuFigueroa97 commented Jan 14, 2025

I have noticed that transient dependency contaminates my environment. That is, without using target_include_library(openssl) openssl is still in the executable. This is because I use curl and libarchive. Is there a way to make this transient dependency private to curl and libarchive, thus avoiding contamination of the environment?

It would be nice if the transient openssl dependency was decommissioned and present only for the necessary ports, in my case curl and libarchive. as long as it remains hidden from others.

I also use fmt and spdlog. Note that both include openssl internally although this should not be the case. When I remove both dependencies from an executable I notice that it warns me about the lack of openssl. it's very strange

@FrankXie05
Copy link
Contributor

I have noticed that transient dependency contaminates my environment. That is, without using target_include_library(openssl) openssl is still in the executable. This is because I use curl and libarchive. Is there a way to make this transient dependency private to curl and libarchive, thus avoiding contamination of the environment?

Openssl is currently exposed as a public (transitive) dependency of curl and libarchive. If it is linked as PUBLIC or INTERFACE the CMake configuration of these libraries, any target that depends on curl and libarchive will integrate the dependency of opnessl.

It would be nice if the transient openssl dependency was decommissioned and present only for the necessary ports, in my case curl and libarchive. as long as it remains hidden from others.

I also use fmt and spdlog. Note that both include openssl internally although this should not be the case. When I remove both dependencies from an executable I notice that it warns me about the lack of openssl. it's very strange

You can limit the displayed features and versions in vcpkg.json in the manifest mode of vcpkg to avoid environmental pollution.
Like:

{
    "dependencies": [
        { "name": "curl", "features": ["ssl"] },
        { "name": "libarchive", "features": ["crypto"] },
        { "name": "openssl", "version>=": "1.1.1" }
    ]
}

However, it should be clear that in vcpkg, the dependency propagation rules are usually determined by the CMake configuration of the library. If curl or libarchive(or others ports) uses PUBLIC or INTERFACE dependencies, all transitive dependencies will be exposed to the dependents. This situation is not unique to vcpkg, but a standard behavior of CMake.

@FrankXie05 FrankXie05 added the category:vcpkg-feature The issue is a new capability of the tool that doesn’t already exist and we haven’t committed label Jan 14, 2025
@FrankXie05
Copy link
Contributor

If the manifest restriction is not possible, you can manually isolate dependencies through cmake. For example, create an INTERFACE library locally or use the --graphviz function to generate a dependency graph (like: fmt or spdlog.) to analyze and view build configuration issues. Make corresponding adjustments through these methods.

Hope to help you. :)

@dg0yt
Copy link
Contributor

dg0yt commented Jan 14, 2025

The input is still to vague to give a good answer.

If curl or libarchive(or others ports) uses PUBLIC or INTERFACE dependencies, all transitive dependencies will be exposed to the dependents.

For static library linkage, even PRIVATE linking will need to pass on transitive link libraries, i.e. linking curl will pull in the openssl libs when curl is built with openssl.

I would like to know if there is a way for all the executables to use the openssl that I configured in my vcpkg.json and not the transient dependency since it contaminates my environment.

From a vcpkg POV, there is only one openssl: the port. It is used to define port dependencies.
If you want to choose system openssl instead, you must use an (almost) empty overlay port so that all reverse dependencies of openssl use the system openssl.

@NahuFigueroa97
Copy link
Author

I understand that openssl is public for curl and for all those who use curl. In my case when I only add spdlog and fmt, it still finds the openssl headers without having added curl.
To solve this, should I add the port overload?
I really need openssl in other executables but I want it to be the one I import from vcpkg, not the one downloaded by curl. It's frustrating not to include curl and still have the openssl headers available without including openssl with the target_include_library

@autoantwort
Copy link
Contributor

it still finds the openssl headers without having added curl

Who is it? Your cmake project?

but I want it to be the one I import from vcpkg, not the one downloaded by curl

The curl port also uses the openssl from vcpkg.

@NahuFigueroa97
Copy link
Author

I don't mind curl downloading openssl, I mind that even without adding curl with target_include_library() it finds openssl headers. This is the vcpkg.json fragment where I have the ports defined

    {
      "name": "curl",
      "version": "8.9.1#0"
    },
    {
      "name": "openssl",
      "version": "3.4.0#0"
    }

This executable makes use of openssl headers and finds them. but I'm not adding them.

set(SRC_DIR ${CMAKE_CURRENT_LIST_DIR}/src)

add_library(zz STATIC
    ${SRC_DIR}/zz.cpp
)
target_include_directories(zz
    PRIVATE
    ${SRC_DIR}
)

target_link_libraries(zz
    PUBLIC
    fmt::fmt-header-only
)

@NahuFigueroa97
Copy link
Author

I will check my dependency tree again, but I don't understand why when I add fmt it finds the openssl headers

@autoantwort
Copy link
Contributor

Then you probably have installed the openssl headers on your system and they are found.

@NahuFigueroa97
Copy link
Author

Then you probably have installed the openssl headers on your system and they are found.

I don't think so, because if I don't include any of the ports that I download vcpkg, it tells me about the error

@NahuFigueroa97
Copy link
Author

I understand that curl does not report errors. But I would expect that fmt, spdlog or any other port that has no relation to openssl would report the error to me.

@autoantwort
Copy link
Contributor

autoantwort commented Jan 14, 2025

Please post your complete vcpkg.json, your CMakeLists.txt and the source file so that one can reproduce what you are describing

@NahuFigueroa97
Copy link
Author

NahuFigueroa97 commented Jan 14, 2025

{
  "dependencies": [
    "benchmark",
    "concurrentqueue",
    "curl",
    "date",
    "flatbuffers",
    "fast-float",
    "fmt",
    "gtest",
    "libmaxminddb",
    "libuv",
    "opentelemetry-cpp",
    "protobuf",
    "pugixml",
    "rapidjson",
    "re2",
    "rocksdb",
    "rxcpp",
    "spdlog",
    "taskflow",
    "uvw",
    "yaml-cpp",
    "cpp-httplib",
    "liblzma",
    "libarchive",
    "openssl"
  ],
  "overrides": [
    {
      "name": "benchmark",
      "version": "1.8.5#0"
    },
    {
      "name": "concurrentqueue",
      "version": "1.0.4#0"
    },
    {
      "name": "curl",
      "version": "8.9.1#0"
    },
    {
      "name": "date",
      "version": "2024-05-14#0"
    },
    {
      "name": "flatbuffers",
      "version": "24.3.25#0"
    },
    {
      "name": "fast-float",
      "version": "6.1.4#0"
    },
    {
      "name": "fmt",
      "version": "8.1.1#2"
    },
    {
      "name": "gtest",
      "version": "1.15.0#0"
    },
    {
      "name": "libmaxminddb",
      "version": "1.9.1#0"
    },
    {
      "name": "libuv",
      "version": "1.48.0#0"
    },
    {
      "name": "opentelemetry-cpp",
      "version": "1.8.3#6"
    },
    {
      "name": "protobuf",
      "version": "3.21.12#4"
    },
    {
      "name": "pugixml",
      "version": "1.14#0"
    },
    {
      "name": "rapidjson",
      "version": "2023-07-17#1"
    },
    {
      "name": "re2",
      "version": "2024-06-01#0"
    },
    {
      "name": "rocksdb",
      "version": "9.2.1#0"
    },
    {
      "name": "rxcpp",
      "version": "4.1.1#1"
    },
    {
      "name": "spdlog",
      "version": "1.14.1#0"
    },
    {
      "name": "taskflow",
      "version": "3.7.0#0"
    },
    {
      "name": "uvw",
      "version": "2.12.1#2"
    },
    {
      "name": "yaml-cpp",
      "version": "0.8.0#0"
    },
    {
      "name": "cpp-httplib",
      "version": "0.16.2#0"
    },
    {
      "name": "liblzma",
      "version": "5.6.3#0"
    },
    {
      "name": "libarchive",
      "version": "3.7.7#0"
    },
    {
      "name": "openssl",
      "version": "3.4.0#0"
    }
  ]
}

# Defs
set(IFACE_DIR ${CMAKE_CURRENT_LIST_DIR}/interface)
set(SRC_DIR ${CMAKE_CURRENT_LIST_DIR}/src)
set(INC_DIR ${CMAKE_CURRENT_LIST_DIR}/include)

## Interface
add_library(builder_ibuilder INTERFACE)
target_include_directories(builder_ibuilder INTERFACE ${IFACE_DIR})
target_link_libraries(builder_ibuilder INTERFACE base) # Base for expression
add_library(builder::ibuilder ALIAS builder_ibuilder)

## Builders Obj Lib
# If debug is enabled, Add the RE2_ON_VALGRIND definition for RE2
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
  add_compile_definitions(RE2_ON_VALGRIND)
endif()

## Lib
SET(BUILDER_PUB_INCS
    ${INC_DIR}
)
SET(BUILDER_PRI_INCS
    ${SRC_DIR}
    ${INC_DIR}/builder
)
add_library(builder STATIC
    ${SRC_DIR}/builder.cpp
    ${SRC_DIR}/policy/factory.cpp
    ${SRC_DIR}/policy/policy.cpp
    ${SRC_DIR}/policy/assetBuilder.cpp
    ${SRC_DIR}/builders/baseHelper.cpp

    # Stage
    ${SRC_DIR}/builders/stage/check.cpp
    ${SRC_DIR}/builders/stage/map.cpp
    ${SRC_DIR}/builders/stage/parse.cpp
    ${SRC_DIR}/builders/stage/normalize.cpp
    ${SRC_DIR}/builders/stage/outputs.cpp
    ${SRC_DIR}/builders/stage/fileOutput.cpp
    ${SRC_DIR}/builders/stage/indexerOutput.cpp

    # Map
    ${SRC_DIR}/builders/opmap/map.cpp
    # TODO: Move to separate files
    ${SRC_DIR}/builders/opmap/opBuilderHelperMap.cpp
    ${SRC_DIR}/builders/opmap/kvdb.cpp
    ${SRC_DIR}/builders/opmap/mmdb.cpp
    ${SRC_DIR}/builders/opmap/activeResponse.cpp
    ${SRC_DIR}/builders/opmap/upgradeConfirmation.cpp
    ${SRC_DIR}/builders/opmap/wdb.cpp

    # Filter
    ${SRC_DIR}/builders/opfilter/filter.cpp
    ${SRC_DIR}/builders/opfilter/startsWith.cpp
    ${SRC_DIR}/builders/opfilter/exists.cpp
    # TODO: Move to separate files
    ${SRC_DIR}/builders/opfilter/opBuilderHelperFilter.cpp

    # Transform
    ${SRC_DIR}/builders/optransform/array.cpp
    ${SRC_DIR}/builders/optransform/hlp.cpp
    ${SRC_DIR}/builders/optransform/sca.cpp
    ${SRC_DIR}/builders/optransform/windows.cpp
)
target_include_directories(builder PUBLIC ${BUILDER_PUB_INCS} PRIVATE ${BUILDER_PRI_INCS})
target_link_libraries(builder
    PUBLIC
    builder::ibuilder
    store::istore
    defs::idefinitions
    schemf::ischema
    base
    kvdb::ikvdb
    geo::igeo
    sockiface::isock
    wdb::iwdb
    indexerconnector::iindexerconnector
    logpar

    PRIVATE
    re2::re2
    logicexpr
    date::date
)

Everything that is public depends on a target called base that only has fmt and spdlog public. As you can see, there are no references to curl. Even so, the openssl headers are in this executable.

There are many cmakelists, but this case particularly calls my attention because I don't use curl anywhere and it still finds openssl.
I have already taken care of removing openssl from the system and I have verified it using any module without including any vcpkg library.

@NahuFigueroa97
Copy link
Author

in the cmake cache I find this: //Path to a library.
OPENSSL_DL_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libdl.a

@NahuFigueroa97
Copy link
Author

Any news regarding this?

@dg0yt
Copy link
Contributor

dg0yt commented Jan 16, 2025

All headers go to <vpckg_installed>/include.

Some packages use a subdir, and export include/subdir as interface include directory. This would give the desired isolation. OTOH this pattern appears to be inconvenient for msbuild users because they have to add the include dir manually to their VS projects.

But many packages, using a subdir or not, expect just include as interface include directory. As soon as one such package (fmt) adds its path to your CMake project, the other package's headers (openssl) are reachable as well.

Normally this isn't a problem unless using greedy autodection in configuration.

Again, vcpkg more or less assumes a single installation of openssl to take part in the build. If you don't want the implementation from the vcpkg port, the proper approach is an overlay port which acts an interface to the external implementation. The link to an example was given in #43248 (reply in thread)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category:vcpkg-feature The issue is a new capability of the tool that doesn’t already exist and we haven’t committed
Projects
None yet
Development

No branches or pull requests

4 participants