diff --git a/.gitignore b/.gitignore index d8a1b8691a..fd77cafd7a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,13 +8,15 @@ *obj/ src/csharp/AssemblyInfo.cs /ort -/build /build_* +build*/ +/test/test_models/* /test/models/* /cache_models /onnxruntime-linux-x64-* *.csv .idea +.venv cache_dir example-models *.onnx @@ -46,4 +48,4 @@ examples/csharp/ModelChat/models /src/java/local.properties /src/java/build /src/java/CMakeFiles -/src/java/CMakeCache.txt \ No newline at end of file +/src/java/CMakeCache.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 492e70c1b0..9c71239018 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,13 @@ else() cmake_minimum_required(VERSION 3.26) endif() +include(cmake/version.cmake) + +project(Generators VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH} LANGUAGES C CXX) + +include(GNUInstallDirs) include(FetchContent) include(CMakeDependentOption) -project(Generators LANGUAGES C CXX) # All Options should be defined in cmake/options.cmake This must be included before any other cmake file is included include(cmake/options.cmake) @@ -98,7 +102,6 @@ endif() include(cmake/ortlib.cmake) - include(cmake/external/onnxruntime_external_deps.cmake) # All Global variables, including GLOB, for the top level CMakeLists.txt should be defined here include(cmake/global_variables.cmake) @@ -158,15 +161,19 @@ find_package(Threads REQUIRED) if(WIN32) add_library(onnxruntime-genai SHARED ${generator_srcs} "${GENERATORS_ROOT}/dll/onnxruntime-genai.rc") target_compile_definitions(onnxruntime-genai PRIVATE VERSION_INFO=\"${VERSION_INFO}\") - target_compile_definitions(onnxruntime-genai PRIVATE VERSION_MAJOR=${VERSION_MAJOR}) - target_compile_definitions(onnxruntime-genai PRIVATE VERSION_MINOR=${VERSION_MINOR}) - target_compile_definitions(onnxruntime-genai PRIVATE VERSION_PATCH=${VERSION_PATCH}) + target_compile_definitions(onnxruntime-genai PRIVATE VERSION_MAJOR=${PROJECT_VERSION_MAJOR}) + target_compile_definitions(onnxruntime-genai PRIVATE VERSION_MINOR=${PROJECT_VERSION_MINOR}) + target_compile_definitions(onnxruntime-genai PRIVATE VERSION_PATCH=${PROJECT_VERSION_PATCH}) target_compile_definitions(onnxruntime-genai PRIVATE VERSION_SUFFIX=${VERSION_SUFFIX}) target_compile_definitions(onnxruntime-genai PRIVATE FILE_NAME=\"onnxruntime-genai.dll\") else() add_library(onnxruntime-genai SHARED ${generator_srcs}) + set_target_properties(onnxruntime-genai PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) endif() +target_include_directories(onnxruntime-genai INTERFACE + $ $) + target_include_directories(onnxruntime-genai PRIVATE ${ORT_HEADER_DIR}) target_include_directories(onnxruntime-genai PRIVATE ${onnxruntime_extensions_SOURCE_DIR}/shared/api) target_link_libraries(onnxruntime-genai PRIVATE onnxruntime_extensions) @@ -174,7 +181,16 @@ target_link_directories(onnxruntime-genai PRIVATE ${ORT_LIB_DIR}) target_link_libraries(onnxruntime-genai PRIVATE Threads::Threads) # The genai library itself is always embedded in the shared library -list(APPEND ortgenai_embed_libs "$") +if(WIN32 OR ANDROID OR IOS) + list(APPEND ortgenai_embed_libs "$") +else() + if (ENABLE_PYTHON) + list(APPEND python_embed_libs "$") + endif() + if (ENABLE_JAVA) + list(APPEND java_embed_libs "$") + endif() +endif() # we keep the shared libraries disconnected on Android as they will come from separate AARs and we don't want to force # the ORT version to match in both. @@ -191,7 +207,6 @@ if(APPLE) target_link_libraries(onnxruntime-genai PRIVATE "-framework Foundation" "-framework CoreML") endif() - # Build all source files using CUDA as a separate shared library we dynamically load at runtime if((USE_CUDA OR USE_TRT_RTX) AND CMAKE_CUDA_COMPILER) # Suppress nvcc warnings: @@ -241,9 +256,8 @@ if((USE_CUDA OR USE_TRT_RTX) AND CMAKE_CUDA_COMPILER) endif() endif() - if(USE_GUIDANCE) - target_include_directories(onnxruntime-genai PUBLIC ${llguidance_SOURCE_DIR}/parser/) + target_include_directories(onnxruntime-genai PRIVATE ${llguidance_SOURCE_DIR}/parser/) target_link_libraries(onnxruntime-genai PRIVATE llguidance) if (WIN32) # bcrypt is needed for the rust std lib diff --git a/benchmark/c/CMakeLists.txt b/benchmark/c/CMakeLists.txt index ed0815cbc8..b079771943 100644 --- a/benchmark/c/CMakeLists.txt +++ b/benchmark/c/CMakeLists.txt @@ -21,13 +21,7 @@ endif() add_executable(model_benchmark ${model_benchmark_srcs}) -target_include_directories(model_benchmark PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/src # directory containing the ort_genai headers -) - -target_link_libraries(model_benchmark PRIVATE onnxruntime-genai ${ONNXRUNTIME_LIB}) - -target_link_directories(model_benchmark PRIVATE ${ORT_LIB_DIR}) +target_link_libraries(model_benchmark PRIVATE onnxruntime-genai) +target_include_directories(model_benchmark PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${model_benchmark_srcs}) diff --git a/build.py b/build.py index ec28740026..1f71204ecb 100644 --- a/build.py +++ b/build.py @@ -85,6 +85,7 @@ class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescript # Default to not building the language bindings parser.add_argument("--build_csharp", action="store_true", help="Build the C# API.") + parser.add_argument("--msbuild_extra_options", nargs="+", action="extend", default=[], help="Extra MSBuild properties (/p:key=value). Provide as key=value.") parser.add_argument("--build_java", action="store_true", help="Build Java bindings.") parser.add_argument( "--publish_java_maven_local", @@ -403,9 +404,11 @@ def _get_csharp_properties(args: argparse.Namespace, ort_lib_dir: Path): ) ort_lib_path = f"/p:OrtLibDir={ort_lib_dir}" - props = [configuration, platform, native_lib_path, ort_lib_path] + msbuild_extra_options = list(args.msbuild_extra_options) + if args.config == "Release" and not [opt for opt in msbuild_extra_options if 'IsReleaseBuild' in opt]: + msbuild_extra_options.append("IsReleaseBuild=True") - return props + return [configuration, platform, native_lib_path, ort_lib_path] + ["/p:" + option for option in msbuild_extra_options] def _run_android_tests(args: argparse.Namespace): @@ -652,6 +655,9 @@ def _get_opencv_toolchain_file(): ) args.test = False + if util.is_windows() and 'Ninja' in args.cmake_generator: + command += ["--compile-no-warning-as-error"] + if args.cmake_extra_defines != []: command += args.cmake_extra_defines @@ -762,13 +768,18 @@ def build_examples(args: argparse.Namespace, env: dict[str, str]): Build the examples. """ examples_dir = REPO_ROOT / "examples" / "c" - build_dir = examples_dir / "build" - - if build_dir.exists(): - log.info(f"Removing existing build directory: {build_dir}") - shutil.rmtree(build_dir) - - build_dir.mkdir() + build_dir = examples_dir / "build" / args.config + + # Removing the build directory will no longer work because of + # the FetchContent used in the examples. It creates the _deps/ + # directory, which contains .git/ subdirectories. Removing those + # requires elevated privileges. + # if build_dir.exists(): + # log.info(f"Removing existing build directory: {build_dir}") + # shutil.rmtree(build_dir) + # + # Do not need to create build dir manually. CMake will do that. + # build_dir.mkdir(parents=True) samples_to_build = [ "-DMODEL_QA=ON", @@ -778,31 +789,50 @@ def build_examples(args: argparse.Namespace, env: dict[str, str]): "-DNEMOTRON_SPEECH=ON" ] - ort_include_dir = REPO_ROOT / "ort" / "include" - ort_lib_dir = REPO_ROOT / "ort" / "lib" - oga_include_dir = REPO_ROOT / "src" - oga_lib_dir = args.build_dir - if util.is_windows(): - # On Windows, the library files are in a subdirectory named after the configuration (e.g. Debug, Release, etc.) - oga_lib_dir = oga_lib_dir / args.config + cmake_prefix_path = args.build_dir.as_posix() + if args.ort_home: + cmake_prefix_path += ";" + (args.ort_home / args.config).as_posix() + else: + ortlib_src_dir = args.build_dir / "_deps" / "ortlib-src" + ort_include_dir = REPO_ROOT / "ort" / "include" + if not ort_include_dir.exists(): + ort_include_dir = ortlib_src_dir / "build" / "native" / "include" + ortlib_runtimes_dir = ortlib_src_dir / "runtimes" + ort_lib_dir = REPO_ROOT / "ort" / "lib" + if not ort_lib_dir.exists(): + if util.is_windows_arm() or (util.is_windows() and (args.arm64 or args.arm64ec)): + ort_lib_dir = ortlib_runtimes_dir / "win-arm64" + elif util.is_windows(): + ort_lib_dir = ortlib_runtimes_dir / "win-x64" + elif args.android: + ort_lib_dir = ortlib_runtimes_dir / "android" + elif util.is_linux_arm() or (util.is_linux() and (args.arm64 or args.arm64ec)): + ort_lib_dir = ortlib_runtimes_dir / "linux-arm64" + elif util.is_linux(): + ort_lib_dir = ortlib_runtimes_dir / "linux-x64" + elif util.is_mac() or args.macos: + ort_lib_dir = ortlib_runtimes_dir / "osx-arm64" + elif args.ios: + ort_lib_dir = ortlib_runtimes_dir / "ios" + elif not util.is_aix(): + raise RuntimeError("'{}': unsupported operating system to build examples for".format(sys.platform)) + samples_to_build += [ + "-DORT_INCLUDE_DIR=" + ort_include_dir.as_posix(), + "-DORT_LIB_DIR=" + (ort_lib_dir / "native").as_posix() + ] cmake_command = ( [ - str(args.cmake_path), + args.cmake_path.as_posix(), "-S", - str(examples_dir), + examples_dir.as_posix(), "-B", - str(build_dir), + build_dir.as_posix(), "-G", args.cmake_generator, + "-DCMAKE_PREFIX_PATH=" + cmake_prefix_path ] + samples_to_build - + [ - "-DORT_INCLUDE_DIR=" + str(ort_include_dir), - "-DORT_LIB_DIR=" + str(ort_lib_dir), - "-DOGA_INCLUDE_DIR=" + str(oga_include_dir), - "-DOGA_LIB_DIR=" + str(oga_lib_dir), - ] ) if args.cmake_generator.startswith("Visual Studio"): @@ -811,7 +841,7 @@ def build_examples(args: argparse.Namespace, env: dict[str, str]): elif args.arm64ec: cmake_command += ["-A", "ARM64EC"] - if args.cmake_extra_defines != []: + if args.cmake_extra_defines: cmake_command += args.cmake_extra_defines util.run(cmake_command, env=env) diff --git a/cmake/global_variables.cmake b/cmake/global_variables.cmake index 687b668a74..ca044eaf17 100644 --- a/cmake/global_variables.cmake +++ b/cmake/global_variables.cmake @@ -1,30 +1,6 @@ # All Global variables for the top level CMakeLists.txt should be defined here -# Define the Version Info -file(READ "VERSION_INFO" ver) -set(VERSION_INFO ${ver}) - -# Example: -# VERSION_INFO: 0.4.0-dev -# VERSION_STR: 0.4.0 -# VERSION_SUFFIX: dev -# VERSION_MAJOR: 0 -# VERSION_MINOR: 4 -# VERSION_PATCH: 0 -string(REPLACE "-" ";" VERSION_LIST ${VERSION_INFO}) -list(GET VERSION_LIST 0 VERSION_STR) -# Check if it is a stable or dev version -list(LENGTH VERSION_LIST VERSION_LIST_LENGTH) -if(VERSION_LIST_LENGTH GREATER 1) - list(GET VERSION_LIST 1 VERSION_SUFFIX) -else() - set(VERSION_SUFFIX "") # Set VERSION_SUFFIX to empty if stable version -endif() -string(REPLACE "." ";" VERSION_LIST ${VERSION_STR}) -list(GET VERSION_LIST 0 VERSION_MAJOR) -list(GET VERSION_LIST 1 VERSION_MINOR) -list(GET VERSION_LIST 2 VERSION_PATCH) - +include_guard() # Define the project directories set(REPO_ROOT ${PROJECT_SOURCE_DIR}) @@ -102,8 +78,8 @@ if (IOS OR MAC_CATALYST) elseif (USE_WINML) message(STATUS "Using WinML, does NOT include ONNX Runtime library, is provied by Windows.") else() - if(NOT EXISTS "${ORT_LIB_DIR}/${ONNXRUNTIME_LIB}") - message(FATAL_ERROR "Expected the ONNX Runtime library to be found at ${ORT_LIB_DIR}/${ONNXRUNTIME_LIB}. Actual: Not found.") + if(NOT EXISTS "${ORT_BIN_DIR}/${ONNXRUNTIME_LIB}") + message(FATAL_ERROR "Expected the ONNX Runtime library to be found at ${ORT_BIN_DIR}/${ONNXRUNTIME_LIB}. Actual: Not found.") endif() endif() diff --git a/cmake/onnxruntime-genai-config.cmake.in b/cmake/onnxruntime-genai-config.cmake.in new file mode 100644 index 0000000000..e0764c608a --- /dev/null +++ b/cmake/onnxruntime-genai-config.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ +if (NOT TARGET onnxruntime::onnxruntime-genai) + include(${CMAKE_CURRENT_LIST_DIR}/onnxruntime-genai-targets.cmake) +endif() +check_required_components(onnxruntime-genai) diff --git a/cmake/ortlib.cmake b/cmake/ortlib.cmake index 65a48aae1d..94d4edd110 100644 --- a/cmake/ortlib.cmake +++ b/cmake/ortlib.cmake @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +include_guard() + if(USE_WINML) message(STATUS "----- Building with WinML support ----- ") @@ -53,6 +55,24 @@ if(USE_WINML) message(STATUS "USE_WINML: ORT_HOME set to: ${ORT_HOME}") endif() +function(_get_target_location_property variable target property) + get_target_property(_result ${target} ${property}) + if(NOT _result) + set(_configuration_types ${CMAKE_CONFIGURATION_TYPES}) + if (NOT _configuration_types) + set(_configuration_types Release;RelWithDebInfo;MinSizeRel;Debug) + endif() + foreach(_build_type ${_configuration_types}) + string(TOUPPER ${_build_type} _build_type) + get_target_property(_result ${target} ${property}_${_build_type}) + if(_result) + break() + endif() + endforeach() + endif() + set(${variable} ${_result} PARENT_SCOPE) +endfunction() + if(ORT_HOME) # If ORT_HOME is specified at build time, use ORT_HOME to get the onnxruntime headers and libraries message(STATUS "Using ONNX Runtime from: ${ORT_HOME} [as provided]") @@ -65,15 +85,45 @@ if(ORT_HOME) # Paths are based on the directory structure of the ORT Android AAR. set(ORT_HEADER_DIR ${ORT_HOME}/headers) set(ORT_LIB_DIR ${ORT_HOME}/jni/${ANDROID_ABI}) + set(ORT_BIN_DIR ${ORT_LIB_DIR}) elseif (IOS OR MAC_CATALYST) set(ORT_HEADER_DIR ${ORT_HOME}/Headers) set(ORT_LIB_DIR ${ORT_HOME}/) + set(ORT_BIN_DIR ${ORT_LIB_DIR}) elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") set(ORT_HEADER_DIR ${ORT_HOME}/include/onnxruntime) + set(ORT_BIN_DIR ${ORT_HOME}/bin) set(ORT_LIB_DIR ${ORT_HOME}/lib) else() - set(ORT_HEADER_DIR ${ORT_HOME}/include) - set(ORT_LIB_DIR ${ORT_HOME}/lib) + find_package(onnxruntime QUIET PATHS ${ORT_HOME}/${CMAKE_BUILD_TYPE} ${ORT_HOME} NO_DEFAULT_PATH) + if(onnxruntime_FOUND) + get_target_property(ORT_HEADER_DIR onnxruntime::onnxruntime INTERFACE_INCLUDE_DIRECTORIES) + _get_target_location_property(_onnxruntime_location onnxruntime::onnxruntime IMPORTED_LOCATION) + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + _get_target_location_property(_onnxruntime_lib onnxruntime::onnxruntime IMPORTED_IMPLIB) + else() + set(_onnxruntime_lib "${_onnxruntime_location}") + endif() + else() + find_file(_onnxruntime_c_api_h onnxruntime_c_api.h REQUIRED + HINTS "${ORT_HOME}" PATH_SUFFIXES include include/onnxruntime) + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + find_file(_onnxruntime_location onnxruntime.dll REQUIRED + HINTS "${ORT_HOME}" PATH_SUFFIXES bin lib) + find_file(_onnxruntime_lib onnxruntime.lib REQUIRED + HINTS "${ORT_HOME}" PATH_SUFFIXES lib) + else() + find_file(_onnxruntime_location ${CMAKE_SHARED_LIBRARY_PREFIX}onnxruntime${CMAKE_SHARED_LIBRARY_SUFFIX} REQUIRED + HINTS "${ORT_HOME}" PATH_SUFFIXES bin lib) + set(_onnxruntime_lib "${_onnxruntime_location}") + endif() + cmake_path(GET _onnxruntime_c_api_h PARENT_PATH ORT_HEADER_DIR) + endif() + if(NOT _onnxruntime_location) + message(FATAL_ERROR "Unable to locate the ONNXRuntime installation or build.") + endif() + cmake_path(GET _onnxruntime_location PARENT_PATH ORT_BIN_DIR) + cmake_path(GET _onnxruntime_lib PARENT_PATH ORT_LIB_DIR) endif() else() # If ORT_HOME is not specified, download the onnxruntime headers and libraries from the nightly feed @@ -125,7 +175,7 @@ else() else() set(ORT_BINARY_PLATFORM "x64") if (APPLE) - if(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64") set(ORT_BINARY_PLATFORM "arm64") endif() set(ORT_LIB_DIR ${ortlib_SOURCE_DIR}/runtimes/osx-${ORT_BINARY_PLATFORM}/native) @@ -147,6 +197,7 @@ else() message(FATAL_ERROR "Auto download ONNX Runtime for this platform is not supported.") endif() endif() + set(ORT_BIN_DIR ${ORT_LIB_DIR}) endif() # Download DML headers and libraries @@ -194,3 +245,4 @@ set(ONNXRUNTIME_LIB_DIR ${ORT_LIB_DIR}) message(STATUS "ORT_HEADER_DIR: ${ORT_HEADER_DIR}") message(STATUS "ORT_LIB_DIR: ${ORT_LIB_DIR}") +message(STATUS "ORT_BIN_DIR: ${ORT_BIN_DIR}") diff --git a/cmake/package.cmake b/cmake/package.cmake index 22e06ae812..55ce19fe66 100644 --- a/cmake/package.cmake +++ b/cmake/package.cmake @@ -1,3 +1,4 @@ + set(ONNXRUNTIME_GENAI_PUBLIC_HEADERS "${PROJECT_SOURCE_DIR}/src/ort_genai_c.h;${PROJECT_SOURCE_DIR}/src/ort_genai.h" ) @@ -6,25 +7,38 @@ set_target_properties( onnxruntime-genai PROPERTIES PUBLIC_HEADER "${ONNXRUNTIME_GENAI_PUBLIC_HEADERS}" ) -install(TARGETS - onnxruntime-genai - LIBRARY DESTINATION lib - RUNTIME DESTINATION lib - ARCHIVE DESTINATION lib - PUBLIC_HEADER DESTINATION include + +install(TARGETS onnxruntime-genai + EXPORT onnxruntime-genaiTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR} ) +export(EXPORT onnxruntime-genaiTargets + FILE ${CMAKE_CURRENT_BINARY_DIR}/onnxruntime-genai-targets.cmake + NAMESPACE onnxruntime:: +) +install( + EXPORT onnxruntime-genaiTargets + FILE onnxruntime-genai-targets.cmake + NAMESPACE onnxruntime:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/onnxruntime-genai +) + if(USE_CUDA OR USE_TRT_RTX) - install(TARGETS - onnxruntime-genai-cuda - LIBRARY DESTINATION lib - RUNTIME DESTINATION lib - ARCHIVE DESTINATION lib + install(TARGETS onnxruntime-genai-cuda + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endif() if (WIN32) - install(FILES $ DESTINATION lib CONFIGURATIONS RelWithDebInfo Debug) + install(FILES $ + DESTINATION ${CMAKE_INSTALL_BINDIR} + CONFIGURATIONS RelWithDebInfo Debug) endif() set(CPACK_PACKAGE_VENDOR "Microsoft") set(CPACK_PACKAGE_NAME "onnxruntime-genai") @@ -82,7 +96,6 @@ install(FILES include(CPack) - # Assemble the Apple static framework (iOS and macOS) if(BUILD_APPLE_FRAMEWORK) # create Info.plist for the framework and podspec for CocoaPods (optional) @@ -144,4 +157,21 @@ if(BUILD_APPLE_FRAMEWORK) copy_if_different ${h_} ${STATIC_FRAMEWORK_HEADER_DIR}/${HEADER_NAME_}) endforeach() -endif() \ No newline at end of file +endif() + +include(CMakePackageConfigHelpers) + +configure_package_config_file( + ${CMAKE_CURRENT_LIST_DIR}/onnxruntime-genai-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/onnxruntime-genai-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/onnxruntime-genai +) +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/onnxruntime-genai-config-version.cmake + VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH} + COMPATIBILITY AnyNewerVersion +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/onnxruntime-genai-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/onnxruntime-genai-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/onnxruntime-genai) diff --git a/cmake/version.cmake b/cmake/version.cmake new file mode 100644 index 0000000000..cd7d56be89 --- /dev/null +++ b/cmake/version.cmake @@ -0,0 +1,29 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +include_guard() + +# Define the Version Info +file(READ "${CMAKE_CURRENT_LIST_DIR}/../VERSION_INFO" ver) +string(STRIP "${ver}" VERSION_INFO) + +# Example: +# VERSION_INFO: 0.4.0-dev +# VERSION_STR: 0.4.0 +# VERSION_SUFFIX: dev +# VERSION_MAJOR: 0 +# VERSION_MINOR: 4 +# VERSION_PATCH: 0 +string(REPLACE "-" ";" VERSION_LIST ${VERSION_INFO}) +list(GET VERSION_LIST 0 VERSION_STR) +# Check if it is a stable or dev version +list(LENGTH VERSION_LIST VERSION_LIST_LENGTH) +if(VERSION_LIST_LENGTH GREATER 1) + list(GET VERSION_LIST 1 VERSION_SUFFIX) +else() + set(VERSION_SUFFIX "") # Set VERSION_SUFFIX to empty if stable version +endif() +string(REPLACE "." ";" VERSION_LIST ${VERSION_STR}) +list(GET VERSION_LIST 0 VERSION_MAJOR) +list(GET VERSION_LIST 1 VERSION_MINOR) +list(GET VERSION_LIST 2 VERSION_PATCH) diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 4e20db2c51..b7b0d838b3 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -1,23 +1,30 @@ -cmake_minimum_required(VERSION 3.18.1) +cmake_minimum_required(VERSION 3.25) + +project(ortgenaiapp LANGUAGES C CXX) -project(ortgenaiapp) set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) -# Download and make available nlohmann/json include(FetchContent) + +# Download and make available nlohmann/json FetchContent_Declare( nlohmann_json GIT_REPOSITORY https://github.com/nlohmann/json.git GIT_TAG v3.12.0 # Or update to latest release + SYSTEM + EXCLUDE_FROM_ALL ) FetchContent_MakeAvailable(nlohmann_json) # Download and make available CLI11 -include(FetchContent) FetchContent_Declare( CLI11 GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git GIT_TAG v2.6.1 # Or update to latest release + SYSTEM + EXCLUDE_FROM_ALL ) FetchContent_MakeAvailable(CLI11) @@ -32,117 +39,66 @@ if(USE_CXX) add_compile_definitions(USE_CXX) endif() -# Set expected library filenames -if(WIN32) - set(ORT_LIB_FILE "onnxruntime.dll") - set(OGA_LIB_FILE "onnxruntime-genai.dll") -elseif(APPLE) - set(ORT_LIB_FILE "libonnxruntime.dylib") - set(OGA_LIB_FILE "libonnxruntime-genai.dylib") -elseif(CMAKE_SYSTEM_NAME MATCHES "AIX") - set(ORT_LIB_FILE "libonnxruntime.a") - set(OGA_LIB_FILE "libonnxruntime-genai.a") -else() - set(ORT_LIB_FILE "libonnxruntime.so") - set(OGA_LIB_FILE "libonnxruntime-genai.so") -endif() - -# Set default variables to examples/c/include and examples/c/lib if not specified -if(NOT ORT_INCLUDE_DIR) - set(ORT_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include") -endif() -if(NOT OGA_INCLUDE_DIR) - set(OGA_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include") -endif() -if(NOT ORT_LIB_DIR) - set(ORT_LIB_DIR "${CMAKE_SOURCE_DIR}/lib") -endif() -if(NOT OGA_LIB_DIR) - set(OGA_LIB_DIR "${CMAKE_SOURCE_DIR}/lib") -endif() - -# Print paths to provided directories -message(STATUS "ORT_INCLUDE_DIR: ${ORT_INCLUDE_DIR}") -message(STATUS "ORT_LIB_DIR: ${ORT_LIB_DIR}") -message(STATUS "OGA_INCLUDE_DIR: ${OGA_INCLUDE_DIR}") -message(STATUS "OGA_LIB_DIR: ${OGA_LIB_DIR}") - -# Store all library files in each directory -file(GLOB ort_libs "${ORT_LIB_DIR}/*") -file(GLOB oga_libs "${OGA_LIB_DIR}/*") +macro(genai_find_dependency id component) + find_package(${component} QUIET HINTS ${${id}_HOME}) + if(NOT ${component}_FOUND) + if(CMAKE_SYSTEM_NAME MATCHES "AIX") + set(${id}_LIB_FILE lib${component}.a) + else() + set(${id}_LIB_FILE ${CMAKE_SHARED_LIBRARY_PREFIX}${component}${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif() + if(NOT ${id}_INCLUDE_DIR OR NOT ${id}_LIB_DIR) + message(FATAL_ERROR "missing required ${id}_INCLUDE_DIR and ${id}_LIB_DIR") + endif() + message(STATUS "${id}_INCLUDE_DIR: ${${id}_INCLUDE_DIR}") + message(STATUS "${id}_LIB_DIR: ${${id}_LIB_DIR}") + add_library(onnxruntime::${component} SHARED IMPORTED) + set_target_properties(onnxruntime::${component} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${${id}_INCLUDE_DIR}) + set_target_properties(onnxruntime::${component} PROPERTIES + IMPORTED_LOCATION "${${id}_LIB_DIR}/${${id}_LIB_FILE}") + if(WIN32) + set_target_properties(onnxruntime::${component} PROPERTIES + IMPORTED_IMPLIB "${${id}_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${component}${CMAKE_STATIC_LIBRARY_SUFFIX}") + endif() + endif() +endmacro() -function(prepare_executable executable) - # Link directory and library for ORT and ORT GenAI - target_link_directories(${executable} PRIVATE ${ORT_LIB_DIR}) - target_link_libraries(${executable} PRIVATE ${ORT_LIB_FILE}) - target_link_directories(${executable} PRIVATE ${OGA_LIB_DIR}) - target_link_libraries(${executable} PRIVATE ${OGA_LIB_FILE}) +genai_find_dependency(ORT onnxruntime) +genai_find_dependency(OGA onnxruntime-genai) - # Set RPATH so the executable can find shared libraries at their build locations +macro(genai_add_example target) + add_executable(${target} ${ARGN}) + target_link_libraries(${target} PRIVATE onnxruntime::onnxruntime-genai + onnxruntime::onnxruntime nlohmann_json::nlohmann_json CLI11::CLI11) if(UNIX) - set_target_properties(${executable} PROPERTIES - BUILD_RPATH "${ORT_LIB_DIR};${OGA_LIB_DIR}" - ) + set_target_properties(${target} PROPERTIES BUILD_RPATH + "$;$") + elseif(WIN32) + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ $ COMMAND_EXPAND_LISTS) endif() - - # Add include directories for each executable - target_include_directories(${executable} PRIVATE ${ORT_INCLUDE_DIR}) - target_include_directories(${executable} PRIVATE ${OGA_INCLUDE_DIR}) - - target_link_libraries(${executable} PUBLIC onnxruntime) - target_link_libraries(${executable} PUBLIC onnxruntime-genai) - - foreach(DEPENDENCY_FILE ${ort_libs}) - if (NOT IS_DIRECTORY ${DEPENDENCY_FILE}) - add_custom_command( - TARGET ${executable} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEPENDENCY_FILE} $ - ) - endif() - endforeach() - - foreach(DEPENDENCY_FILE ${oga_libs}) - if (NOT IS_DIRECTORY ${DEPENDENCY_FILE}) - add_custom_command( - TARGET ${executable} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEPENDENCY_FILE} $ - ) - endif() - endforeach() -endfunction() +endmacro() set(EXAMPLES_SOURCE_DIR ${CMAKE_SOURCE_DIR}/src) if(MODEL_CHAT) - add_executable(model_chat ${EXAMPLES_SOURCE_DIR}/model_chat.cpp ${EXAMPLES_SOURCE_DIR}/common.cpp) - prepare_executable(model_chat) - target_link_libraries(model_chat PRIVATE nlohmann_json::nlohmann_json) - target_link_libraries(model_chat PRIVATE CLI11::CLI11) + genai_add_example(model_chat ${EXAMPLES_SOURCE_DIR}/model_chat.cpp ${EXAMPLES_SOURCE_DIR}/common.cpp) endif() if(MODEL_QA) - add_executable(model_qa ${EXAMPLES_SOURCE_DIR}/model_qa.cpp ${EXAMPLES_SOURCE_DIR}/common.cpp) - prepare_executable(model_qa) - target_link_libraries(model_qa PRIVATE nlohmann_json::nlohmann_json) - target_link_libraries(model_qa PRIVATE CLI11::CLI11) + genai_add_example(model_qa ${EXAMPLES_SOURCE_DIR}/model_qa.cpp ${EXAMPLES_SOURCE_DIR}/common.cpp) endif() if(MODEL_MM) - add_executable(model_mm ${EXAMPLES_SOURCE_DIR}/model_mm.cpp ${EXAMPLES_SOURCE_DIR}/common.cpp) - prepare_executable(model_mm) - target_link_libraries(model_mm PRIVATE nlohmann_json::nlohmann_json) - target_link_libraries(model_mm PRIVATE CLI11::CLI11) + genai_add_example(model_mm ${EXAMPLES_SOURCE_DIR}/model_mm.cpp ${EXAMPLES_SOURCE_DIR}/common.cpp) endif() if(WHISPER) - add_executable(whisper ${EXAMPLES_SOURCE_DIR}/whisper.cpp ${EXAMPLES_SOURCE_DIR}/common.cpp) - prepare_executable(whisper) - target_link_libraries(whisper PRIVATE nlohmann_json::nlohmann_json) - target_link_libraries(whisper PRIVATE CLI11::CLI11) + genai_add_example(whisper ${EXAMPLES_SOURCE_DIR}/whisper.cpp ${EXAMPLES_SOURCE_DIR}/common.cpp) endif() if(NEMOTRON_SPEECH) - add_executable(nemotron_speech ${EXAMPLES_SOURCE_DIR}/nemotron_speech.cpp) - prepare_executable(nemotron_speech) - target_link_libraries(nemotron_speech PRIVATE nlohmann_json::nlohmann_json) + genai_add_example(nemotron_speech ${EXAMPLES_SOURCE_DIR}/nemotron_speech.cpp) endif() diff --git a/src/csharp/Microsoft.ML.OnnxRuntimeGenAI.sln b/src/csharp/Microsoft.ML.OnnxRuntimeGenAI.sln index 087d849e38..eff2c4f21e 100644 --- a/src/csharp/Microsoft.ML.OnnxRuntimeGenAI.sln +++ b/src/csharp/Microsoft.ML.OnnxRuntimeGenAI.sln @@ -9,12 +9,15 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU RelWithDebInfo|Any CPU = RelWithDebInfo|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {58AF8A7E-2395-42B7-9030-389B813BF04D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {58AF8A7E-2395-42B7-9030-389B813BF04D}.Debug|Any CPU.Build.0 = Debug|Any CPU {58AF8A7E-2395-42B7-9030-389B813BF04D}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|Any CPU {58AF8A7E-2395-42B7-9030-389B813BF04D}.RelWithDebInfo|Any CPU.Build.0 = RelWithDebInfo|Any CPU + {58AF8A7E-2395-42B7-9030-389B813BF04D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58AF8A7E-2395-42B7-9030-389B813BF04D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/java/CMakeLists.txt b/src/java/CMakeLists.txt index 26a9798d8c..849e90bbdc 100644 --- a/src/java/CMakeLists.txt +++ b/src/java/CMakeLists.txt @@ -107,14 +107,10 @@ set(ORT_PACKAGE_LIB_DIR ${JAVA_NATIVE_LIB_DIR}/ai/onnxruntime/native/${JAVA_OS_A file(MAKE_DIRECTORY ${ORT_PACKAGE_LIB_DIR}) # Add the native genai libraries to the native-lib dir -# Instead of hard-coding the .dll/.so name, we iterate over the list -# of libraries the build system has identified as dependencies. -foreach(LIB_FILE ${ortgenai_embed_libs}) - add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${LIB_FILE} - ${JAVA_PACKAGE_LIB_DIR}/) -endforeach() +add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${ortgenai_embed_libs} ${java_embed_libs} + ${JAVA_PACKAGE_LIB_DIR}/) # Add the JNI bindings to the native-jni dir add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD @@ -233,15 +229,17 @@ if (ENABLE_TESTS) WORKING_DIRECTORY ${JAVA_SRC_ROOT}) endif() + set(_onnxruntime_bin_dir ${ORT_LIB_DIR}) if(WIN32) set(ONNXRUNTIME_GENAI_DEPENDENCY "*.dll") + set(_onnxruntime_bin_dir ${ORT_BIN_DIR}) elseif(APPLE) set(ONNXRUNTIME_GENAI_DEPENDENCY "*.dylib") else() set(ONNXRUNTIME_GENAI_DEPENDENCY "*.so") endif() - file(GLOB ort_native_libs "${ORT_LIB_DIR}/${ONNXRUNTIME_GENAI_DEPENDENCY}") + file(GLOB ort_native_libs "${_onnxruntime_bin_dir}/${ONNXRUNTIME_GENAI_DEPENDENCY}") # Copy ORT native libs for Java tests foreach(LIB_FILE ${ort_native_libs}) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index d15b4b3430..fc1085a599 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -50,7 +50,7 @@ if(BUILD_WHEEL) add_custom_command(TARGET python POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy - ${ortgenai_embed_libs} $ + ${ortgenai_embed_libs} ${python_embed_libs} $ ${WHEEL_TARGET_NAME} COMMENT "Copying files to wheel directory: ${WHEEL_TARGET_NAME}" ) diff --git a/tools/python/util/__init__.py b/tools/python/util/__init__.py index c12376cc72..8eca7971d1 100644 --- a/tools/python/util/__init__.py +++ b/tools/python/util/__init__.py @@ -4,5 +4,5 @@ from .android import * from .dependency_resolver import copy_dependencies, download_dependencies from .logger import get_logger -from .platform_helpers import is_aix, is_linux, is_mac, is_windows, is_windows_arm +from .platform_helpers import is_aix, is_linux, is_linux_arm, is_mac, is_windows, is_windows_arm from .run import run diff --git a/tools/python/util/platform_helpers.py b/tools/python/util/platform_helpers.py index 0bee1796fd..6a21401cd5 100644 --- a/tools/python/util/platform_helpers.py +++ b/tools/python/util/platform_helpers.py @@ -17,6 +17,10 @@ def is_linux(): return sys.platform.startswith("linux") +def is_linux_arm(): + return is_linux() and "arm" in platform.machine().lower() + + def is_aix(): return sys.platform.startswith("aix")