-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
What is your question?
Context
I am developing a C++ library (e.g. MyLib) that will be consumed by a React Native iOS application. The consumer cannot use Conan because React Native for iOS relies on CocoaPods/Swift Package Manager, which does not support Conan integration. Therefore, I need to create a fully self-contained package that includes all necessary headers and binaries.
The Problem
My library (MyLib) depends on third-party libraries (e.g., boost, nlohmann_json, etc.) and exposes their types in my public API headers in certain contexts. I need to distribute a pre-compiled binary package that includes:
- My library,
MyLib, headers and binaries - All necessary third-party headers and binaries used in
MyLib's public API
In addition even if react supported conan I still rather package these third-party libs together to avoid any ABI mismatches that may not directly appear or even fail, and avoid doing something like adding a package_info for requirements.
Example of the concern:
// MyLib.h (Public Header)
#pragma once
#include <fmt/core.h>
namespace mylib {
struct LogContext {
fmt::memory_buffer buffer; // Size/alignment depends on how fmt was compiled
};
void process(LogContext& ctx);
}If the consumer were using Conan, they might rebuild fmt with different compiler flags, causing ABI mismatches with my pre-compiled binary. Since memory layout of fmt::memory_buffer could vary based on compilation options, this would lead to undefined behavior.
However, since my consumer cannot use Conan at all, I need to bundle everything together into a self-contained package.
Attempted Solutions
Option 1: Using conan deploy with custom deployer
- Created a separate
conanfile.pywith onlyMyLibas a requirement
from pathlib import Path
from conan import ConanFile
class DeployConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
def set_version(self):
# Read version from parent directory's VERSION file
version_file = Path(self.recipe_folder).parent / "VERSION"
self.my_lib_version = version_file.read_text().strip()
def requirements(self):
self.requires(f"MyLib/{self.my_lib_version}")
- This allowed Conan to resolve and fetch my library within the final output as well as all transitive dependencies
- Implemented a custom
deploy.pyscript to selectively copy only the dependencies exposed in public headers
from pathlib import Path
import shutil
PACKAGES_TO_DEPLOY = [
"MyLib",
"boost",
"range-v3",
"fmt",
"nlohmann_json",
]
def deploy(graph, output_folder, **kwargs):
"""Custom deployer that only copies specified packages."""
output_path = Path(output_folder)
deployed = set()
# Use graph.nodes to access ALL packages (including hidden/transitive)
for node in graph.nodes:
if node.ref is None:
continue
pkg_folder = node.conanfile.package_folder
if pkg_folder is None:
continue
pkg_name = node.ref.name
if pkg_name in PACKAGES_TO_DEPLOY:
src = Path(pkg_folder)
dest = output_path / pkg_name
if dest.exists():
shutil.rmtree(dest)
shutil.copytree(src, dest)
deployed.add(pkg_name)
print(f"Deployed: {pkg_name} -> {dest}")
# Verify all required packages were deployed
missing = set(PACKAGES_TO_DEPLOY) - deployed
if missing:
raise RuntimeError(f"Failed to deploy packages (not found in graph): {', '.join(sorted(missing))}")
-
Deploy specifying275 the custom
deploy.pyscript shown above with a local folder -
Problem: This approach did not include header-only libraries, and we couldn't find a clean (non-hacky) way to handle them. It would however include properly all build libraries that were not header only.
Option 2: Modify MyLib's conanfile.py package method
- Instead of using
conan deploy, modify MyLib's ownconanfile.py - In the
package()method, copy third-party headers and libraries directly
def package(self):
cmake = CMake(self)
cmake.install()
self._copy_third_party_headers()
self._copy_third_party_libraries()
- Advantage: In this context, we have direct access to dependency information
- Question: Is this the recommended approach?
Have you read the CONTRIBUTING guide?
- I've read the CONTRIBUTING guide