-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Build Windows ARM64X binaries as part of packaging pipeline #27316
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
Merged
Merged
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
4689b51
save work
edgchen1 8f66c20
save work
edgchen1 88ee8a7
save work
edgchen1 1fc9fb2
revert tools/ci_build/github/azure-pipelines/qnn-ep-nuget-packaging-p…
edgchen1 616efc3
update build-win-arm64x-steps.yml to get all other build params from …
edgchen1 56890f2
update qnn-ep-win for updated template
edgchen1 a707e93
save work
edgchen1 c729bb7
fix quoting
edgchen1 3f00648
remove BuildConfig parameter from arm64x build template
edgchen1 8194aa5
update diplayname
edgchen1 2b354c3
add set-variable.yml
edgchen1 1ab1e29
Merge remote-tracking branch 'origin/main' into edgchen1/arm64x_binaries
edgchen1 fc1d429
build arm64x in py-win-cpu.yml
edgchen1 025193f
rename parameters, make quoting consistent
edgchen1 99f3d46
make variable setting message consistent with other steps
edgchen1 b000c8c
revert changes to py-win-cpu.yml
edgchen1 30807cd
Merge remote-tracking branch 'origin/main' into edgchen1/arm64x_binaries
edgchen1 602c996
Add samples/cxx example. Thanks AI!
edgchen1 bd0ef50
update readme to not specify location for archive
edgchen1 4c6f7ba
add binary archive tests to package test pipeline
edgchen1 a0fbcda
try to fix stage name by using underscore instead of hyphen
edgchen1 ed28bb1
remove indentation to avoid newlines
edgchen1 bfd5d47
use arm64 windows pool
edgchen1 8d679f6
try another pool
edgchen1 3bf406d
use separate build directory for win-arm64x x64 build
edgchen1 6e356cc
change win-arm64x test to build/run arm64ec instead of x64
edgchen1 bc15455
TEST - see if win-arm64 fails for arm64ec build
edgchen1 45cda25
Revert "TEST - see if win-arm64 fails for arm64ec build"
edgchen1 2106825
use job variables, reduce platform-specific stuff
edgchen1 002f3d6
make previousStageName param optional, make agentPool param an object…
edgchen1 b44f8be
add agent setup steps parameter and use it to set up build tools on m…
edgchen1 a6adfda
fix path to template
edgchen1 1801cd8
remove extra indentation
edgchen1 d7bf27d
Merge remote-tracking branch 'origin/main' into edgchen1/arm64x_binaries
edgchen1 b8e9904
fix lint issues
edgchen1 e7290e4
update generate_model.py imports
edgchen1 4ae443b
Merge remote-tracking branch 'origin/main' into edgchen1/arm64x_binaries
edgchen1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. | ||
|
|
||
| cmake_minimum_required(VERSION 3.28) | ||
|
|
||
| project(onnxruntime_sample CXX) | ||
|
|
||
| set(CMAKE_CXX_STANDARD 20) | ||
|
|
||
| foreach(VAR IN ITEMS ORT_LIBRARY_DIR ORT_HEADER_DIR) | ||
| if (NOT DEFINED ${VAR}) | ||
| message(FATAL_ERROR "Required variable ${VAR} is not set. " | ||
| "Set ORT_LIBRARY_DIR to the ONNX Runtime lib directory and " | ||
| "ORT_HEADER_DIR to the ONNX Runtime include directory.") | ||
| endif() | ||
| endforeach() | ||
|
|
||
| # Resolve to absolute paths | ||
| get_filename_component(ORT_LIBRARY_DIR "${ORT_LIBRARY_DIR}" ABSOLUTE) | ||
| get_filename_component(ORT_HEADER_DIR "${ORT_HEADER_DIR}" ABSOLUTE) | ||
|
|
||
| # | ||
| # onnxruntime_sample_program | ||
| # | ||
| block() | ||
| add_executable(onnxruntime_sample_program) | ||
|
|
||
| target_sources(onnxruntime_sample_program PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/main.cc) | ||
|
|
||
| target_include_directories(onnxruntime_sample_program PRIVATE ${ORT_HEADER_DIR}) | ||
|
|
||
| target_link_directories(onnxruntime_sample_program PRIVATE ${ORT_LIBRARY_DIR}) | ||
| target_link_libraries(onnxruntime_sample_program PRIVATE onnxruntime) | ||
|
|
||
| # Copy ONNX Runtime shared libraries next to the executable. | ||
| # Collect shared library files from the ORT library directory based on platform. | ||
| if (WIN32) | ||
| file(GLOB ORT_SHARED_LIBS "${ORT_LIBRARY_DIR}/*.dll") | ||
| elseif (APPLE) | ||
| file(GLOB ORT_SHARED_LIBS "${ORT_LIBRARY_DIR}/*.dylib") | ||
| else() | ||
| file(GLOB ORT_SHARED_LIBS "${ORT_LIBRARY_DIR}/*.so" "${ORT_LIBRARY_DIR}/*.so.*") | ||
| endif() | ||
|
|
||
| add_custom_command(TARGET onnxruntime_sample_program POST_BUILD | ||
| COMMAND ${CMAKE_COMMAND} -E copy_if_different | ||
| ${ORT_SHARED_LIBS} | ||
| $<TARGET_FILE_DIR:onnxruntime_sample_program> | ||
| ) | ||
| endblock() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| # ONNX Runtime C++ Sample | ||
|
|
||
| A minimal C++ program demonstrating basic ONNX Runtime inference. It loads an ONNX model that adds two float tensors (`C = A + B`), runs inference, and verifies the result. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - CMake 3.28 or later | ||
| - C++20 compatible compiler (e.g., Visual Studio 2022) | ||
| - An ONNX Runtime release package (download from [GitHub releases](https://github.com/microsoft/onnxruntime/releases)) | ||
| - For model generation: | ||
| - Python with the `onnx` package | ||
|
|
||
| ## Directory Structure | ||
|
|
||
| ``` | ||
| samples/cxx/ | ||
| ├── CMakeLists.txt # Build configuration | ||
| ├── main.cc # Sample program source | ||
| ├── add_model.onnx # ONNX model (C = A + B) | ||
| ├── generate_model.py # Script to generate the ONNX model | ||
| └── README.md # This file | ||
| ``` | ||
|
|
||
| ## Steps | ||
|
|
||
| ### 1. Extract the ONNX Runtime package | ||
|
|
||
| Download and extract an ONNX Runtime release archive. For example: | ||
|
|
||
| ``` | ||
| tar -xf onnxruntime-win-x64-1.25.0.zip | ||
| ``` | ||
|
|
||
| This creates a directory like `onnxruntime-win-x64-1.25.0/` containing `include/` and `lib/` subdirectories. | ||
|
|
||
| ### 2. [Optional] Generate the ONNX model | ||
|
|
||
| ``` | ||
| cd samples/cxx | ||
| pip install onnx | ||
| python generate_model.py | ||
| ``` | ||
|
|
||
| This creates `add_model.onnx` in the current directory. | ||
|
|
||
| ### 3. Configure and build | ||
|
|
||
| From the `samples/cxx` directory: | ||
|
|
||
| **Windows:** | ||
| ``` | ||
| cmake -S . -B build ^ | ||
| -DORT_HEADER_DIR:PATH=path\to\onnxruntime-win-x64-1.25.0\include ^ | ||
| -DORT_LIBRARY_DIR:PATH=path\to\onnxruntime-win-x64-1.25.0\lib | ||
| cmake --build build --config Release | ||
| ``` | ||
|
|
||
| **Linux / macOS:** | ||
| ``` | ||
| cmake -S . -B build \ | ||
| -DORT_HEADER_DIR:PATH=path/to/onnxruntime-linux-x64-1.25.0/include \ | ||
| -DORT_LIBRARY_DIR:PATH=path/to/onnxruntime-linux-x64-1.25.0/lib | ||
| cmake --build build --config Release | ||
| ``` | ||
|
|
||
| Adjust the paths to match your extracted package name and location. | ||
|
|
||
| The build automatically copies the ONNX Runtime shared libraries next to the executable. | ||
|
|
||
| #### CMake Variables | ||
|
|
||
| | Variable | Description | | ||
| |---|---| | ||
| | `ORT_HEADER_DIR` | Path to the ONNX Runtime `include` directory | | ||
| | `ORT_LIBRARY_DIR` | Path to the ONNX Runtime `lib` directory | | ||
|
|
||
| ### 4. Run | ||
|
|
||
| **Windows:** | ||
| ``` | ||
| build\Release\onnxruntime_sample_program.exe | ||
| ``` | ||
|
|
||
| **Linux / macOS:** | ||
| ``` | ||
| ./build/onnxruntime_sample_program | ||
| ``` | ||
|
|
||
| You can also pass a model path as an argument: | ||
| ``` | ||
| onnxruntime_sample_program path/to/add_model.onnx | ||
| ``` |
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
|
||
| # Licensed under the MIT License. | ||
|
|
||
| """Generate a simple ONNX model that computes C = A + B. | ||
|
|
||
| Inputs: | ||
| A : float tensor of shape [1, 3] | ||
| B : float tensor of shape [1, 3] | ||
|
|
||
| Output: | ||
| C : float tensor of shape [1, 3] | ||
|
|
||
| Usage: | ||
| pip install onnx | ||
| python generate_model.py | ||
| """ | ||
|
|
||
| from onnx import TensorProto, helper, save_model | ||
| from onnx.checker import check_model | ||
|
|
||
|
|
||
edgchen1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| def main(): | ||
| # Define inputs and output | ||
| a = helper.make_tensor_value_info("A", TensorProto.FLOAT, [1, 3]) | ||
| b = helper.make_tensor_value_info("B", TensorProto.FLOAT, [1, 3]) | ||
| c = helper.make_tensor_value_info("C", TensorProto.FLOAT, [1, 3]) | ||
|
|
||
| # Create the Add node | ||
| add_node = helper.make_node("Add", inputs=["A", "B"], outputs=["C"]) | ||
|
|
||
| # Build the graph and model | ||
| graph = helper.make_graph([add_node], "add_graph", [a, b], [c]) | ||
| model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) | ||
|
|
||
| # Validate and save | ||
| check_model(model) | ||
| save_model(model, "add_model.onnx") | ||
| print("Saved add_model.onnx") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| // Sample program demonstrating basic ONNX Runtime C++ API usage. | ||
| // Loads a simple ONNX model (C = A + B), runs inference, and prints the result. | ||
| // | ||
| // Generate the model first: python generate_model.py | ||
|
|
||
| #include <array> | ||
| #include <cstdint> | ||
| #include <cstdlib> | ||
| #include <filesystem> | ||
|
Check warning on line 12 in samples/cxx/main.cc
|
||
| #include <iostream> | ||
| #include <stdexcept> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #include "onnxruntime_cxx_api.h" | ||
|
Check warning on line 18 in samples/cxx/main.cc
|
||
|
|
||
| // Throw std::runtime_error if `condition` is false. Includes file and line info. | ||
| #define THROW_IF_NOT(condition) \ | ||
| do { \ | ||
| if (!(condition)) { \ | ||
| throw std::runtime_error(std::string(__FILE__) + ":" + \ | ||
| std::to_string(__LINE__) + ": " + \ | ||
| "check failed: " #condition); \ | ||
| } \ | ||
| } while (0) | ||
|
|
||
| int main(int argc, char* argv[]) { | ||
| try { | ||
| // ----------------------------------------------------------------------- | ||
| // 1. Initialize the ONNX Runtime environment | ||
| // ----------------------------------------------------------------------- | ||
| Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "onnxruntime_sample"); | ||
| std::cout << "ONNX Runtime version: " << Ort::GetVersionString() << "\n\n"; | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // 2. Create session options (could add execution providers here) | ||
| // ----------------------------------------------------------------------- | ||
| Ort::SessionOptions session_options; | ||
| session_options.SetIntraOpNumThreads(1); | ||
| session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_BASIC); | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // 3. Load the ONNX model from a file | ||
| // Generate with: python generate_model.py | ||
| // ----------------------------------------------------------------------- | ||
| const std::filesystem::path model_path = (argc > 1) ? argv[1] : "add_model.onnx"; | ||
| std::cout << "Loading model: " << model_path.string() << "\n"; | ||
|
|
||
| Ort::Session session(env, model_path.native().c_str(), session_options); | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // 4. Query model metadata: input/output names and shapes | ||
| // ----------------------------------------------------------------------- | ||
| Ort::AllocatorWithDefaultOptions allocator; | ||
|
|
||
| const size_t num_inputs = session.GetInputCount(); | ||
| const size_t num_outputs = session.GetOutputCount(); | ||
| std::cout << "Model inputs: " << num_inputs << "\n"; | ||
| std::cout << "Model outputs: " << num_outputs << "\n"; | ||
|
|
||
| // Collect input/output names | ||
| std::vector<std::string> input_names; | ||
| std::vector<std::string> output_names; | ||
|
|
||
| for (size_t i = 0; i < num_inputs; ++i) { | ||
| auto name = session.GetInputNameAllocated(i, allocator); | ||
| std::cout << " Input " << i << ": " << name.get() << "\n"; | ||
| input_names.emplace_back(name.get()); | ||
| } | ||
| for (size_t i = 0; i < num_outputs; ++i) { | ||
| auto name = session.GetOutputNameAllocated(i, allocator); | ||
| std::cout << " Output " << i << ": " << name.get() << "\n"; | ||
| output_names.emplace_back(name.get()); | ||
| } | ||
| std::cout << "\n"; | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // 5. Prepare input tensors | ||
| // ----------------------------------------------------------------------- | ||
| // Our model expects two float tensors of shape [1, 3]. | ||
| constexpr int64_t batch_size = 1; | ||
| constexpr int64_t num_elements = 3; | ||
| const std::array<int64_t, 2> input_shape = {batch_size, num_elements}; | ||
|
|
||
| std::array<float, num_elements> input_a = {1.0f, 2.0f, 3.0f}; | ||
| std::array<float, num_elements> input_b = {4.0f, 5.0f, 6.0f}; | ||
|
|
||
| auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); | ||
|
|
||
| auto tensor_a = Ort::Value::CreateTensor<float>( | ||
| memory_info, input_a.data(), input_a.size(), | ||
| input_shape.data(), input_shape.size()); | ||
|
|
||
| auto tensor_b = Ort::Value::CreateTensor<float>( | ||
| memory_info, input_b.data(), input_b.size(), | ||
| input_shape.data(), input_shape.size()); | ||
|
|
||
| THROW_IF_NOT(tensor_a.IsTensor()); | ||
| THROW_IF_NOT(tensor_b.IsTensor()); | ||
|
|
||
| // The Run() API expects arrays of C strings for input/output names. | ||
| std::vector<const char*> input_name_ptrs; | ||
| std::vector<const char*> output_name_ptrs; | ||
| for (const auto& n : input_names) input_name_ptrs.push_back(n.c_str()); | ||
| for (const auto& n : output_names) output_name_ptrs.push_back(n.c_str()); | ||
|
|
||
| std::array<Ort::Value, 2> input_tensors{std::move(tensor_a), std::move(tensor_b)}; | ||
|
Check warning on line 110 in samples/cxx/main.cc
|
||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // 6. Run inference | ||
| // ----------------------------------------------------------------------- | ||
| std::cout << "Running inference...\n"; | ||
|
|
||
| Ort::RunOptions run_options; | ||
| auto output_tensors = session.Run( | ||
| run_options, | ||
| input_name_ptrs.data(), input_tensors.data(), input_tensors.size(), | ||
| output_name_ptrs.data(), output_name_ptrs.size()); | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // 7. Process output | ||
| // ----------------------------------------------------------------------- | ||
| THROW_IF_NOT(!output_tensors.empty() && output_tensors[0].IsTensor()); | ||
|
|
||
| const float* output_data = output_tensors[0].GetTensorData<float>(); | ||
| auto type_info = output_tensors[0].GetTensorTypeAndShapeInfo(); | ||
| size_t output_count = type_info.GetElementCount(); | ||
|
|
||
| std::cout << "\nInputs:\n"; | ||
| std::cout << " A = ["; | ||
| for (size_t i = 0; i < input_a.size(); ++i) { | ||
| std::cout << (i ? ", " : "") << input_a[i]; | ||
| } | ||
| std::cout << "]\n"; | ||
|
|
||
| std::cout << " B = ["; | ||
| for (size_t i = 0; i < input_b.size(); ++i) { | ||
| std::cout << (i ? ", " : "") << input_b[i]; | ||
| } | ||
| std::cout << "]\n"; | ||
|
|
||
| std::cout << "\nOutput (A + B):\n"; | ||
| std::cout << " C = ["; | ||
| for (size_t i = 0; i < output_count; ++i) { | ||
| std::cout << (i ? ", " : "") << output_data[i]; | ||
| } | ||
| std::cout << "]\n"; | ||
|
|
||
| // Verify correctness | ||
| bool correct = true; | ||
| for (size_t i = 0; i < num_elements; ++i) { | ||
| if (output_data[i] != input_a[i] + input_b[i]) { | ||
| correct = false; | ||
| break; | ||
| } | ||
| } | ||
| std::cout << "\nResult: " << (correct ? "PASS" : "FAIL") << "\n"; | ||
|
|
||
| return correct ? EXIT_SUCCESS : EXIT_FAILURE; | ||
| } catch (const Ort::Exception& e) { | ||
| std::cerr << "ONNX Runtime error: " << e.what() << "\n"; | ||
| return EXIT_FAILURE; | ||
| } catch (const std::exception& e) { | ||
| std::cerr << "Error: " << e.what() << "\n"; | ||
| return EXIT_FAILURE; | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.