diff --git a/.github/workflows/python-wheel-workflow.yml b/.github/workflows/python-wheel-workflow.yml index 4504bd40f..c80403251 100644 --- a/.github/workflows/python-wheel-workflow.yml +++ b/.github/workflows/python-wheel-workflow.yml @@ -114,6 +114,8 @@ jobs: CIBW_PLATFORM: ${{ matrix.os }} CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-*" CIBW_SKIP: "*-musllinux_*" + # Use uv on macOS to avoid transient GitHub rate limits when cibuildwheel + CIBW_BUILD_FRONTEND: ${{ matrix.os == 'macos' && 'build[uv]' || 'build' }} # Pin arch to the matrix platform CIBW_ARCHS: ${{ matrix.platform }} CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.os == 'linux' && format('manylinux{0}', matrix.manylinux) || '' }} @@ -232,7 +234,11 @@ jobs: run: | set -euxo pipefail python -m pip install --upgrade pip - python -m pip install packaging cibuildwheel + if [ "${{ matrix.os }}" = "macos" ]; then + python -m pip install packaging "cibuildwheel[uv]>=2.22" + else + python -m pip install packaging "cibuildwheel>=2.22" + fi mkdir -p python/dist python -m cibuildwheel --output-dir python/dist "$PKGDIR" diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index f1fa70e98..954442dc0 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -115,8 +115,11 @@ endif() if (APPLE) set(CMAKE_MACOSX_RPATH ON) + # Ensure relocatability on macOS + set(CMAKE_INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR}") elseif(UNIX) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,$ORIGIN") + # $ORIGIN allows the library to find dependencies relative to its own path + set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") endif () set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g -fno-omit-frame-pointer") @@ -145,6 +148,7 @@ endif() # ------------------------------------------------------------------------------ include(CheckLibraryExists) include(GNUInstallDirs) +include(CMakePackageConfigHelpers) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) @@ -189,6 +193,17 @@ macro(find_yaml_cpp) set(CMAKE_WARN_DEPRECATED ON CACHE BOOL "" FORCE) endmacro() +macro(install_graphar_target target) + # install + install(TARGETS ${target} graphar_thirdparty + EXPORT graphar-targets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) +endmacro() + # Implementations of lisp "car" and "cdr" functions macro(GRAPHAR_CAR var) set(${var} ${ARGV1}) @@ -277,6 +292,143 @@ function(graphar_create_merged_static_lib output_target) add_dependencies(${output_target} ${output_target}_merge) endfunction() +macro(build_graphar_thirdparty) + file(GLOB_RECURSE THIRDPARTY_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/mini-yaml/yaml/*.cpp) + add_library(graphar_thirdparty STATIC ${THIRDPARTY_SRC_FILES}) + target_include_directories(graphar_thirdparty PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty) + target_compile_features(graphar_thirdparty PRIVATE cxx_std_17) + if(NOT MSVC) + target_compile_options(graphar_thirdparty PRIVATE -fPIC -w) + endif() +endmacro() + +macro(build_graphar) + build_graphar_thirdparty() + file(GLOB_RECURSE CORE_SRC_FILES "src/graphar/*.cc") + + if(GRAPHAR_BUILD_STATIC) + add_library(graphar STATIC ${CORE_SRC_FILES}) + else() + add_library(graphar SHARED ${CORE_SRC_FILES}) + endif() + + install_graphar_target(graphar) + + target_compile_features(graphar PRIVATE cxx_std_${GAR_CXX_STANDARD}) + + target_include_directories(graphar + PUBLIC + $ + $ + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty + ) + + if(GRAPHAR_BUILD_STATIC) + target_link_libraries(graphar PUBLIC graphar_thirdparty ${CMAKE_DL_LIBS}) + else() + target_link_libraries(graphar PRIVATE graphar_thirdparty ${CMAKE_DL_LIBS}) + endif() + + set(ARROW_LIB_SUFFIX "shared") + if(USE_STATIC_ARROW) + set(ARROW_LIB_SUFFIX "static") + endif() + + set(ARROW_DEPS + Arrow::arrow_${ARROW_LIB_SUFFIX} + Parquet::parquet_${ARROW_LIB_SUFFIX} + ArrowDataset::arrow_dataset_${ARROW_LIB_SUFFIX} + ) + if(ArrowAcero_FOUND) + list(APPEND ARROW_DEPS ArrowAcero::arrow_acero_${ARROW_LIB_SUFFIX}) + endif() + + if(APPLE) + target_link_libraries(graphar PUBLIC -Wl,-force_load ${ARROW_DEPS}) + elseif(MSVC) + target_link_libraries(graphar PUBLIC ${ARROW_DEPS}) + else() + target_link_libraries(graphar PUBLIC + -Wl,--exclude-libs,ALL + -Wl,--whole-archive + ${ARROW_DEPS} + -Wl,--no-whole-archive + ) + endif() +endmacro() + +macro(build_graphar_with_arrow_bundled) + build_graphar_thirdparty() + file(GLOB_RECURSE CORE_SRC_FILES "src/graphar/*.cc") + if(GRAPHAR_BUILD_STATIC) + add_library(graphar STATIC ${CORE_SRC_FILES}) + else() + add_library(graphar SHARED ${CORE_SRC_FILES}) + endif() + install_graphar_target(graphar) + target_compile_features(graphar PRIVATE cxx_std_${GAR_CXX_STANDARD}) + target_include_directories(graphar PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty) + target_include_directories(graphar SYSTEM BEFORE PRIVATE ${GAR_ARROW_INCLUDE_DIR}) + if(GRAPHAR_BUILD_STATIC) + target_link_libraries(graphar PUBLIC graphar_thirdparty ${CMAKE_DL_LIBS}) + else() + target_link_libraries(graphar PRIVATE graphar_thirdparty ${CMAKE_DL_LIBS}) + endif() + + set(GAR_BUNDLED_DEPS_STATIC_LIBS) + list(APPEND GAR_BUNDLED_DEPS_STATIC_LIBS + gar_arrow_static + gar_arrow_compute_static + gar_parquet_static + gar_dataset_static + gar_acero_static + gar_arrow_bundled_dependencies_static) + graphar_car(_FIRST_LIB ${GAR_BUNDLED_DEPS_STATIC_LIBS}) + graphar_cdr(_OTHER_LIBS ${GAR_BUNDLED_DEPS_STATIC_LIBS}) + + graphar_create_merged_static_lib(graphar_bundled_dependencies + NAME + graphar_bundled_dependencies + ROOT + ${_FIRST_LIB} + TO_MERGE + ${_OTHER_LIBS}) + # We can't use install(TARGETS) here because + # graphar_bundled_dependencies is an IMPORTED library. + get_target_property(graphar_bundled_dependencies_path graphar_bundled_dependencies + IMPORTED_LOCATION) + install(FILES ${CMAKE_BINARY_DIR}/${graphar_bundled_dependencies_path} ${INSTALL_IS_OPTIONAL} + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + string(APPEND ARROW_PC_LIBS_PRIVATE " -lgraphar_bundled_dependencies") + list(INSERT ARROW_STATIC_INSTALL_INTERFACE_LIBS 0 "graphar_bundled_dependencies") + + if(APPLE) + find_package(Protobuf REQUIRED) + target_link_libraries(graphar PRIVATE -Wl,-force_load + graphar_bundled_dependencies + protobuf::libprotobuf + "-framework CoreFoundation" + "-framework Security" + "-framework Network") + elseif(MSVC) + # MSVC doesn't support GNU ld-style -Wl flags. + target_link_libraries(graphar PRIVATE graphar_bundled_dependencies) + else() + target_link_libraries(graphar PRIVATE -Wl,--exclude-libs,ALL + graphar_bundled_dependencies) + endif() + + # if OpenSSL library exists, link the OpenSSL library. + # OpenSSL has to be linked after GAR_ARROW_BUNDLED_DEPS_STATIC_LIB + if(OPENSSL_FOUND) + target_link_libraries(graphar PUBLIC OpenSSL::SSL) + endif() + if (CURL_FOUND) + target_link_libraries(graphar PUBLIC ${CURL_LIBRARIES}) + endif() +endmacro() + # ------------------------------------------------------------------------------ # building or find third party library # ------------------------------------------------------------------------------ @@ -396,9 +548,9 @@ install(FILES "${PROJECT_BINARY_DIR}/graphar-config.cmake" install(EXPORT graphar-targets FILE graphar-targets.cmake + NAMESPACE graphar:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/graphar ) - # ------------------------------------------------------------------------------ # Format code & cpplint # ------------------------------------------------------------------------------ diff --git a/cpp/graphar-config.in.cmake b/cpp/graphar-config.in.cmake index 05bb4d541..62fdfe832 100644 --- a/cpp/graphar-config.in.cmake +++ b/cpp/graphar-config.in.cmake @@ -23,9 +23,23 @@ # GRAPHAR_INCLUDE_DIRS - include directories for graphar # GRAPHAR_LIBRARIES - libraries to link against +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + set(GRAPHAR_HOME "${CMAKE_CURRENT_LIST_DIR}/../../..") + +if(NOT @BUILD_ARROW_FROM_SOURCE@) + find_dependency(Arrow REQUIRED) + find_dependency(Parquet REQUIRED) + find_dependency(ArrowDataset REQUIRED) + if(@Arrow_VERSION@ VERSION_GREATER_EQUAL "12.0.0") + find_dependency(ArrowAcero) + endif() +endif() + include("${CMAKE_CURRENT_LIST_DIR}/graphar-targets.cmake") -set(GRAPHAR_LIBRARIES graphar) -set(GRAPHAR_INCLUDE_DIR "${GRAPHAR_HOME}/include") -set(GRAPHAR_INCLUDE_DIRS "${GRAPHAR_INCLUDE_DIR}") +set(GRAPHAR_LIBRARIES graphar::graphar) +get_target_property(GRAPHAR_INCLUDE_DIRS graphar::graphar INTERFACE_INCLUDE_DIRECTORIES) +set(GRAPHAR_INCLUDE_DIR ${GRAPHAR_INCLUDE_DIRS}) diff --git a/python/README.md b/python/README.md index c6a5e8ff5..70325da9f 100644 --- a/python/README.md +++ b/python/README.md @@ -1,12 +1,12 @@ # GraphAr Python SDK -GraphAr Python SDK provides Python bindings for the GraphAr C++ library, allowing user to work with GraphAr formatted graph data in Python environments. It includes both a high-level API for data manipulation and a command-line interface for common operations. +GraphAr Python SDK provides Python bindings for the GraphAr C++ library, allowing users to work with GraphAr formatted graph data in Python environments. It includes both a high-level API for data manipulation and a command-line interface for common operations. ## Installation ### Prerequisites -- Python >= 3.7 +- Python >= 3.9 - pip (latest version recommended) - CMake >= 3.15 (for building from source) - Apache Arrow >= 12.0 (for building from source)