Ctrl K
ComunidadGuías…

conanfile.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import json
import os

from conan import ConanFile
from conan.errors import ConanException, ConanInvalidConfiguration
from conan.tools.build import can_run, check_min_cppstd
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain
from conan.tools.sbom import cyclonedx_1_6

required_conan_version = ">=2.26.0"


class Memgraph(ConanFile):
    name = "memgraph"
    version = "0.0.1"
    package_type = "application"
    license = "https://memgraph.com/legal"
    url = "https://github.com/memgraph/memgraph"
    homepage = "https://memgraph.com"
    description = "In-memory graph database"
    settings = "os", "compiler", "build_type", "arch"

    options = {
        # Build only the MAGE query modules: trims the dependency graph to
        # what src/mage/ links against (fmt, boost, gtest) and configures
        # CMake with MG_BUILD_MEMGRAPH=OFF / MG_BUILD_MAGE=ON. Used by
        # `./build.sh --mage only`.
        "mage_only": [True, False],
        # Build against the toolchain produced by environment/toolchain and ship its
        # C++ runtime. Hosts that build with their own compiler turn this off, and the
        # profile that describes such a host is where it belongs.
        "bundled_toolchain": [True, False],
    }

    exports_sources = (
        "CMakeLists.txt",
        "cmake/*",
        "src/*",
        "libs/*",
        "include/*",
        "tests/*",
        "query_modules/*",
        "release/*",
        "tools/*",
        "licenses/*",
        "config/*",
        "import/*",
    )

    default_options = {
        "mage_only": False,
        "bundled_toolchain": True,
        "aws-sdk-cpp/*:config": True,
        "aws-sdk-cpp/*:s3": True,
        "aws-sdk-cpp/*:monitoring": False,
        "aws-sdk-cpp/*:text-to-speech": False,
        "aws-sdk-cpp/*:queues": False,
        "aws-sdk-cpp/*:sqs": False,
        "aws-sdk-cpp/*:access-management": False,
        "aws-sdk-cpp/*:cognito-identity": True,
        "aws-sdk-cpp/*:iam": False,
        "aws-sdk-cpp/*:identity-management": True,
        "aws-sdk-cpp/*:transfer": True,
        # Disable saslauthd in cyrus-sasl — it adds -lcrypt (system libcrypt.so)
        # whose crypt_rn symbol collides with our vendored libbcrypt's crypt_rn,
        # causing bcrypt's self-test to fail. saslauthd is a Unix auth daemon
        # irrelevant to Kafka SASL client usage.
        "cyrus-sasl/*:with_saslauthd": False,
        "boost/*:without_stacktrace": True,
        "boost/*:without_locale": True,
        "arrow/*:with_s3": True,
        "arrow/*:with_snappy": True,
        "arrow/*:with_mimalloc": False,
        "librdkafka/*:ssl": True,
        "librdkafka/*:sasl": True,
        "mgclient/*:with_cpp": True,
        "jemalloc/*:prefix": "je_",
        "jemalloc/*:enable_cxx": False,
        "jemalloc/*:enable_fill": False,
        "jemalloc/*:lg_page": "12",
        "jemalloc/*:lg_hugepage": "21",
        # NOTE: percpu_arena can bind threads to per-DB arenas on hosts with sparse CPU
        # sets (jemalloc#2054); guarded at runtime by EnsureCpuArenaCoverage() (db_arena.hpp).
        "jemalloc/*:malloc_conf": "retain:false,percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000",
        "rapidcheck/*:enable_gtest": True,
        "rapidcheck/*:enable_gmock": True,
        "gflags/*:nothreads": False,
        "gflags/*:namespace": "google;gflags",
        "nuraft/*:asio": "standalone",
        "rocksdb/*:with_gflags": True,
        "rocksdb/*:use_rtti": True,
        # Disable io_uring async I/O path in rocksdb's POSIX env. Avoids
        # pulling liburing into the static link; flip to True (pulls
        # liburing via Conan) to opt back in.
        "rocksdb/*:with_liburing": False,
        "openssl/*:shared": True,
        "zlib/*:shared": True,
    }

    def requirements(self):
        # Dependencies MAGE links against; everything below the mage_only
        # early-return is memgraph-only.
        # force=True makes boost both a direct require (so CMakeDeps generates
        # full Boost::headers config) and overrides transitive boost ranges
        self.requires("boost/1.91.0-memgraph", force=True)
        self.requires("fmt/12.2.0", force=True)
        self.requires("nlohmann_json/3.11.3-memgraph")
        self.requires("libuuid/1.0.3")

        if self.options.mage_only:
            return

        # Direct dependencies — packages we #include or link against directly
        self.requires("abseil/20250512.1")
        self.requires("antlr4-cppruntime/4.13.2")
        self.requires("arrow/22.0.0")
        self.requires("asio/1.36.0")
        self.requires("aws-sdk-cpp/1.11.692")
        self.requires("bzip2/1.0.8")
        self.requires("cppitertools/2.2")
        self.requires("croncpp/2023.03.30")
        self.requires("ctre/3.10.0")
        self.requires("gflags/2.2.0-memgraph", force=True)
        self.requires("jemalloc/5.2.1-memgraph")
        self.requires("libbcrypt/1.0-memgraph")
        self.requires("librdkafka/2.14.2")
        self.requires("librdtsc/0.3-memgraph")
        if self.settings.os == "Linux":
            # seccomp is a Linux kernel interface and its recipe only supports Linux, so the
            # dependency cannot be resolved elsewhere. src/auth still calls into it
            # unconditionally, so a non-Linux build gets as far as compiling and then fails
            # there; making that optional is separate work.
            self.requires("libseccomp/2.6.0", options={"shared": True})
        self.requires("mgclient/1.8.0")
        self.requires("nuraft/2.1.0-memgraph")
        # Whether this is shared is set by "openssl/*:shared" in default_options, not here.
        # Do not remove `override=True`: it pins one OpenSSL version across the graph.
        self.requires("openssl/3.0.18", override=True)
        self.requires("protobuf/3.21.12")
        self.requires("pulsar-client-cpp/4.0.0-memgraph")
        self.requires("range-v3/0.12.0")
        self.requires("rocksdb/8.1.1-memgraph")
        self.requires("simdjson/4.2.2")
        self.requires("spdlog/1.17.0")
        self.requires("strong_type/v15")
        self.requires("usearch/2.21.4")
        self.requires("zlib/1.3.1", override=True)
        self.requires("prometheus-cpp/1.3.0")

        # Version overrides — pin transitive dependency versions
        self.requires("libcurl/8.17.0", override=True)
        self.requires("snappy/1.2.1", override=True)

    def build_requirements(self):
        self.tool_requires("cmake/4.3.3")  # cmake >= 4.4.0 shows scary errors about modules - TODO(matt): fix
        self.tool_requires("ninja/[>=1.13 <2]")
        self.tool_requires("ccache/4.12.3-memgraph")

        # force=True overrides older gtest pinned by transitive dependencies
        self.test_requires("gtest/[>=1.17 <2]", force=True)

        if self.options.mage_only:
            return

        self.tool_requires("antlr4/4.13.1")
        self.test_requires("benchmark/[>=1.9 <2]")
        self.test_requires("rapidcheck/cci.20231215")
        self.test_requires("approvaltests.cpp/10.13.0")

    def validate(self):
        """Validate configuration before generation"""
        if self.settings.os not in ("Linux", "FreeBSD"):
            raise ConanInvalidConfiguration(
                f"Unsupported OS: {self.settings.os}. Only Linux and FreeBSD are supported."
            )

        user_toolchain = self.conf.get("tools.cmake.cmaketoolchain:user_toolchain")
        if user_toolchain:
            # user_toolchain can be a list or a single path
            toolchains = user_toolchain if isinstance(user_toolchain, list) else [user_toolchain]
            for toolchain_path in toolchains:
                if not os.path.exists(toolchain_path):
                    raise ConanException(
                        f"CMake user toolchain file does not exist: {toolchain_path}\n"
                        f"This is typically configured via the profile. "
                        f"Make sure MG_TOOLCHAIN_ROOT environment variable is set correctly."
                    )

    def validate_build(self):
        """Validate build configuration"""
        # Memgraph requires C++20 or higher
        check_min_cppstd(self, "20")

    def package_id(self):
        # Remove compiler version from package_id for applications
        # Keep build_type to maintain separate Debug/Release binaries
        del self.info.settings.compiler

    # TODO(matt): remove this hack so that builds end up in the subdirectory named after the build type
    # This will require fixing a bunch of the hard-coded paths in the testing code.
    def layout(self):
        # Custom layout to put everything in build/ instead of build/Release or build/RelWithDebInfo
        self.folders.build = "build"
        self.folders.generators = "build/generators"
        self.folders.package = "build/package"

    def generate(self):
        deps = CMakeDeps(self)
        deps.generate()
        tc = CMakeToolchain(self)

        # Automatically set sanitizer CMake flags based on compiler settings
        if self.settings.get_safe("compiler.asan"):
            tc.cache_variables["ASAN"] = "ON"

        if self.settings.get_safe("compiler.ubsan"):
            tc.cache_variables["UBSAN"] = "ON"

        if self.settings.get_safe("compiler.tsan"):
            tc.cache_variables["TSAN"] = "ON"

        if self.options.mage_only:
            tc.cache_variables["MG_BUILD_MEMGRAPH"] = "OFF"
            tc.cache_variables["MG_BUILD_MAGE"] = "ON"

        tc.cache_variables["MG_BUNDLED_TOOLCHAIN"] = "ON" if self.options.bundled_toolchain else "OFF"

        tc.generate()

        # SBOM generation
        sbom = cyclonedx_1_6(self, name="memgraph", add_build=False, add_tests=False)
        out_dir = os.path.join(self.generators_folder, "sbom")
        os.makedirs(out_dir, exist_ok=True)
        out_path = os.path.join(out_dir, "memgraph-sbom.cdx.json")
        with open(out_path, "w") as f:
            json.dump(sbom, f, indent=2)

        self.output.success(f"CYCLONEDX SBOM CREATED -> {out_path}")

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()
        # Only run unit tests if we can run them (not cross-compiling)
        if can_run(self) and not self.options.mage_only:
            cmake.ctest(cli_args=["-R", "memgraph__unit", "--output-on-failure"])

    def package(self):
        # NOTE we still can't package because ATM we exports_sources which means:
        # - we are not a git repo
        # - releases/get_version.py will fail
        cmake = CMake(self)
        cmake.install()

    def package_info(self):
        # Memgraph is an application, so we declare the bin directory
        # This allows tool_requires consumers to find memgraph in PATH
        self.cpp_info.bindirs = ["bin"]