Skip to content
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

Using FetchContent to fetch libdawn.dylib from github when library not found #44

Merged
merged 9 commits into from
Aug 12, 2024

Conversation

kagurazaka-ayano
Copy link
Contributor

This enables the project to be fetched with cmake FetchContent and to be directly built with cmake without calling the python script.

Solution to this issue

@austinvhuang austinvhuang self-assigned this Aug 10, 2024
@austinvhuang
Copy link
Contributor

This looks good overall, thanks! Tagging @MichealReed as well. A question - I'd expect a build to go down one of two mutually exclusive paths:

Mixing these two could raise potential issues since webgpu.h is generated by the build itself. Perhaps there's a flag/option that toggles between the two, but currently it seems to do both at the moment.

Copy link
Contributor

@MichealReed MichealReed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like a good approach to fall back to downloading if not found. @austinvhuang how often do you think people will want to actually change and build their own dawnlib? We may be able to get by with downloads being the default or only support path for CMake?

cmake/gpu.cmake Outdated
endif()
FetchContent_Declare(
libdawn
URL https://github.com/austinvhuang/dawn-artifacts/releases/download/prerelease/libdawn.${libdawn_ext}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if they're hosted yet but we should use the libdawn_${ARCH}_${BUILD_TYPE} convention unless @austinvhuang wants to migrate away from that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For windows yes but windows libraries are in another place. Under this url it's just libdawn.{so/dylib}. Maybe I can add one for Windows with the architecture and build type for windows.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we were going to structure all the libs with this sort of convention, could be mistaken, need Austin to clarify. Other OS will have debug/release/architecture differences too, so I think we wanted to capture all with a generalized approach.

cmake/gpu.cmake Outdated
message("libdawn not found, try downloading from the release")
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(libdawn_ext "dylib")
elseif(UNIX)
Copy link
Contributor

@MichealReed MichealReed Aug 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will definitely fail on windows until we get artifacts hosted for windows and this to accommodate the naming convention. Biggest challenge is debug/release builds with pre-downloaded artifacts. @austinvhuang weren't you thinking about using those google built libs instead of hosting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inside this else statement the system cannot be Windows, I can add download step to windows (i.e. line 53)

@MichealReed
Copy link
Contributor

Maybe we should follow the @jgh- approach here https://github.com/jgh-/webgpu-workbench/blob/main/cmake/dawn.cmake

@kagurazaka-ayano
Copy link
Contributor Author

Maybe we should follow the @jgh- approach here https://github.com/jgh-/webgpu-workbench/blob/main/cmake/dawn.cmake

True... this will build the dawn lib according to the os. Let me try it in my fork to see if this works.

cmake/gpu.cmake Outdated Show resolved Hide resolved
@kagurazaka-ayano
Copy link
Contributor Author

Maybe we should follow the @jgh- approach here https://github.com/jgh-/webgpu-workbench/blob/main/cmake/dawn.cmake

Well I'm trying to use similar grammar in the script but it just stucks in one place and stop responding.

@MichealReed
Copy link
Contributor

MichealReed commented Aug 11, 2024

@austinvhuang I investigated downloading the artifacts from the dawn CI. The API requires a token for this -- https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#download-an-artifact

we likely could set this up via CI though

https://github.com/marketplace/actions/download-workflow-artifact

This script hits the forbidden from lack of token

import requests
import zipfile
import os

REPO_OWNER = 'google'
REPO_NAME = 'dawn'
WORKFLOW_FILE_NAME = 'ci.yml'  # The specific workflow file name

def get_latest_successful_workflow_run():
    url = f'https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/actions/workflows/{WORKFLOW_FILE_NAME}/runs?status=success'
    response = requests.get(url)
    response.raise_for_status()
    runs = response.json()['workflow_runs']
    if not runs:
        raise Exception('No successful workflow runs found')
    return runs[0]['id']  # Get the latest successful run ID

def list_artifacts(run_id):
    url = f'https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/actions/runs/{run_id}/artifacts'
    response = requests.get(url)
    response.raise_for_status()
    return response.json()['artifacts']

def download_artifact(artifact):
    download_url = artifact['archive_download_url']
    response = requests.get(download_url, stream=True)
    response.raise_for_status()
    with open(f"{artifact['name']}.zip", 'wb') as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)

    with zipfile.ZipFile(f"{artifact['name']}.zip", 'r') as zip_ref:
        zip_ref.extractall(artifact['name'])
    os.remove(f"{artifact['name']}.zip")

def main():
    print("Fetching the latest successful workflow run ID...")
    latest_run_id = get_latest_successful_workflow_run()
    
    print(f"Listing artifacts for run ID: {latest_run_id}...")
    artifacts = list_artifacts(latest_run_id)
    
    for artifact in artifacts:
        print(f"Downloading and extracting {artifact['name']}...")
        download_artifact(artifact)
        print(f"Extracted {artifact['name']}")

if __name__ == "__main__":
    main()

@MichealReed
Copy link
Contributor

Maybe we should follow the @jgh- approach here https://github.com/jgh-/webgpu-workbench/blob/main/cmake/dawn.cmake

Well I'm trying to use similar grammar in the script but it just stucks in one place and stop responding.

Yeah I think the repository is just huge, mine downloaded over 10GB. Building each run might not be so viable, we'll likely run into cache issues. May be better to initialize the repository for dawn using a submodule rather than relying on cmake. Probably we will have to find a way to automate the artifact downloads instead.

@jgh-
Copy link
Collaborator

jgh- commented Aug 11, 2024

You have to make sure you aren't downloading the submodules. I believe the dawn repository itself is reasonably sized but once you start cloning the submodules it gets huge. The dependency python script it runs is sufficient to get everything it needs to be built.

@kagurazaka-ayano
Copy link
Contributor Author

You have to make sure you aren't downloading the submodules. I believe the dawn repository itself is reasonably sized but once you start cloning the submodules it gets huge. The dependency python script it runs is sufficient to get everything it needs to be built.

Yeah after disabling download submodules it is much faster, but I'm having this error:


|| -- Using Dawn backend
|| -- Using Dawn backend for WebGPU
|| CMake Warning (dev) at /opt/homebrew/Cellar/cmake/3.30.0/share/cmake/Modules/FetchContent.cmake:1953 (message):
||   Calling FetchContent_Populate(dawn) is deprecated, call
||   FetchContent_MakeAvailable(dawn) instead.  Policy CMP0169 can be set to OLD
||   to allow FetchContent_Populate(dawn) to be called directly for now, but the
||   ability to call it with declared details will be removed completely in a
||   future version.
|| Call Stack (most recent call first):
||   third_party/fetchcontent/webgpu-src/cmake/FetchDawn.cmake:53 (FetchContent_Populate)
||   third_party/fetchcontent/webgpu-src/CMakeLists.txt:23 (include)
|| This warning is for project developers.  Use -Wno-dev to suppress it.
|| 
|| -- Dawn build D3D11 backend: OFF
|| -- Dawn build D3D12 backend: OFF
|| -- Dawn build Metal backend: ON
|| -- Dawn build Vulkan backend: OFF
|| -- Dawn build OpenGL backend: OFF
|| -- Dawn build OpenGL ES backend: OFF
|| -- Dawn build Null backend: OFF
|| -- Dawn build with asserts in all configurations: OFF
|| -- Dawn build Wayland support: OFF
|| -- Dawn build X11 support: OFF
|| -- Dawn build GLFW support: ON
|| -- Dawn build Windows UI support: OFF
|| -- Dawn build and use DXC: OFF
|| -- Dawn disable DXC asserts in debug builds: OFF
|| -- Dawn build samples: OFF
|| -- Dawn build Node bindings: OFF
|| -- Dawn build Swiftshader: OFF
|| -- Dawn build benchmarks: OFF
|| -- Dawn build PIC: OFF
|| -- Dawn build with ASAN: OFF
|| -- Dawn build with TSAN: OFF
|| -- Dawn build with MSAN: OFF
|| -- Dawn build with UBSAN: OFF
|| -- Tint build command line executable tools: ON
|| -- Tint build SPIR-V reader: OFF
|| -- Tint build WGSL reader: ON
|| -- Tint build GLSL writer: OFF
|| -- Tint build GLSL validator: ON
|| -- Tint build HLSL writer: OFF
|| -- Tint build MSL writer: ON
|| -- Tint build SPIR-V writer: OFF
|| -- Tint build WGSL writer: ON
|| -- Tint build Syntax Tree writer: OFF
|| -- Tint build fuzzers: OFF
|| -- Tint build AST fuzzer: OFF
|| -- Tint build regex fuzzer: OFF
|| -- Tint build benchmarks: OFF
|| -- Tint build tests: OFF
|| -- Tint build checking [chromium-style]: OFF
|| -- Tint external benchmark corpus dir: 
|| -- Dawn: using python at /opt/homebrew/Frameworks/Python.framework/Versions/3.12/bin/python3.12
|| -- Running fetch_dawn_dependencies:
|| -- -- Listing dependencies from /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src
|| -- -- Fetching dependency 'third_party/abseil-cpp'
|| -- -- Fetching dependency 'third_party/glfw'
|| -- -- Fetching dependency 'third_party/jinja2'
|| -- -- Fetching dependency 'third_party/khronos/EGL-Registry'
|| -- -- Fetching dependency 'third_party/khronos/OpenGL-Registry'
|| -- -- Fetching dependency 'third_party/libprotobuf-mutator/src'
|| -- -- Fetching dependency 'third_party/markupsafe'
|| -- -- Fetching dependency 'third_party/glslang/src'
|| -- -- Listing dependencies from /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/glslang/src
|| -- -- Fetching dependency 'third_party/spirv-headers/src'
|| -- -- Fetching dependency 'third_party/spirv-tools/src'
|| -- -- Listing dependencies from /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/spirv-tools/src
|| -- -- Fetching dependency 'third_party/vulkan-headers/src'
|| -- -- Fetching dependency 'third_party/vulkan-loader/src'
|| -- -- Fetching dependency 'third_party/vulkan-utility-libraries/src'
|| -- Dawn: using SPIRV-Headers at /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/spirv-headers/src
|| -- Dawn: using SPIRV-Tools at /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/spirv-tools/src
|| -- spirv-tools not linked - illegal SPIRV may be generated for HLSL
|| -- Dawn: using GLFW at /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/glfw
|| -- Including Cocoa support
|| -- Dawn: using Abseil at /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/abseil-cpp
|| -- Dawn: using Vulkan-Headers at /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/vulkan-headers/src
|| -- Dawn: using jinja2 at /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/jinja2
|| -- Dawn: using markupsafe at /Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src/third_party/markupsafe
|| -- FETCHING DAWN FOR BUILDING DYNAMIC LIBRARY
|| CMake Error at third_party/fetchcontent/dawn_ext-src/CMakeLists.txt:262 (add_library):
||   add_library cannot create target "dawn_public_config" because another
||   target with the same name already exists.  The existing target is an
||   interface library created in source directory
||   "/Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src".
||   See documentation for policy CMP0002 for more details.
|| 
|| 
|| CMake Error at third_party/fetchcontent/dawn_ext-src/CMakeLists.txt:270 (add_library):
||   add_library cannot create target "dawn_internal_config" because another
||   target with the same name already exists.  The existing target is an
||   interface library created in source directory
||   "/Users/ayano/Documents/developing/projects/gpu.cpp/third_party/fetchcontent/dawn-src".
||   See documentation for policy CMP0002 for more details.
|| 
|| 
|| -- Dawn build D3D11 backend: OFF
|| -- Dawn build D3D12 backend: OFF
|| -- Dawn build Metal backend: ON
|| -- Dawn build Vulkan backend: OFF
|| -- Dawn build OpenGL backend: OFF
|| -- Dawn build OpenGL ES backend: OFF
|| -- Dawn build Emscripten: OFF
|| -- Dawn build Null backend: OFF
|| -- Dawn enable SPIR-V validation: OFF
|| -- Dawn build with asserts in all configurations: OFF
|| -- Dawn build Wayland support: OFF
|| -- Dawn build X11 support: OFF
|| -- Dawn build GLFW support: ON
|| -- Dawn build Windows UI support: OFF
|| -- Dawn build and use DXC: OFF
|| -- Dawn enable DXC asserts in non-debug builds: ON
|| -- Dawn build samples: OFF
|| -- Dawn build Node bindings: OFF
|| -- Dawn build Swiftshader: OFF
|| -- Dawn build benchmarks: OFF
|| -- Dawn build PIC: OFF
|| -- Dawn build with ASAN: OFF
|| -- Dawn build with TSAN: OFF
|| -- Dawn build with MSAN: OFF
|| -- Dawn build with UBSAN: OFF
|| -- Tint build command line executable tools: ON
|| -- Tint build SPIR-V reader: OFF
|| -- Tint build WGSL reader: ON
|| -- Tint build GLSL writer: OFF
|| -- Tint build GLSL validator: ON
|| -- Tint build HLSL writer: OFF
|| -- Tint build MSL writer: ON
|| -- Tint build SPIR-V writer: OFF
|| -- Tint build WGSL writer: ON
|| -- Tint build Syntax Tree writer: OFF
|| -- Tint build fuzzers: OFF
|| -- Tint build IR binary: ON
|| -- Tint build IR fuzzer: OFF
|| -- Tint build benchmarks: OFF
|| -- Tint build tests: OFF
|| -- Tint build checking [chromium-style]: OFF
|| -- Dawn: using python at /opt/homebrew/Frameworks/Python.framework/Versions/3.12/bin/python3.12
|| CMake Error at third_party/fetchcontent/dawn_ext-src/src/tint/CMakeLists.txt:50 (message):
||   Building IR binary format 'TINT_BUILD_IR_BINARY' is enabled, but building
||   protobuf 'DAWN_BUILD_PROTOBUF' is not
|| 
|| 
|| -- Configuring incomplete, errors occurred!
|| Exited with code 1

probably because dawn is previously built by webgpu and some variables haven't been cleaned yet.

@MichealReed
Copy link
Contributor

MichealReed commented Aug 11, 2024

Might be better to initialize a submodule under third_party/local for dawn and then approach like

# Set the DAWN_EXT_SOURCE_DIR to the local Dawn directory
set(DAWN_EXT_SOURCE_DIR "${TARGET_DIR}/third_party/local/dawn" CACHE STRING "Path to the local Dawn source directory")

execute_process(
    COMMAND python3 ${DAWN_EXT_SOURCE_DIR}/tools/fetch_dawn_dependencies.py
    WORKING_DIRECTORY ${DAWN_EXT_SOURCE_DIR}
    RESULT_VARIABLE FETCH_RESULT
)

set(DESIRED_CMAKE_ARGS
    -DDAWN_DISABLE_LOGGING=ON
    -DCMAKE_POSITION_INDEPENDENT_CODE=ON
)

include(ExternalProject)
ExternalProject_Add(
    dawn_project
    PREFIX dawn
    SOURCE_DIR ${DAWN_EXT_SOURCE_DIR}
    CMAKE_ARGS ${DESIRED_CMAKE_ARGS}
    BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR>
    INSTALL_DIR ${INSTALL_DIR}
    STEP_TARGETS install
)

add_custom_target(install_dawn
    DEPENDS dawn_project-install
)

@MichealReed
Copy link
Contributor

Got this working fairly well here, feel free to take any of it as inspiration for this refactor 👍

https://github.com/MichealReed/minigpu/tree/master/minigpu_ffi/src

@MichealReed
Copy link
Contributor

google/dawn#20 opened this, the dawn builds will error unless you add googletest to the dependencies list to init.

@kagurazaka-ayano
Copy link
Contributor Author

In this version the project will be installed to third_party/local/dawn/install. Maybe the next step is to move the libs and include files to their designated place.

@austinvhuang
Copy link
Contributor

austinvhuang commented Aug 12, 2024

Catching up on this thread.

Thanks for investigating - I love the idea of getting artifacts from Dawn directly, last time I tried it out - I was able to download manually however, OSX security restrictions meant I could not use the mac dylib artifacts after downloading them because they're not signed (iirc couldn't even get to a dialog to override the restriction). Doesn't have to be solved in this PR though.

If there's a workaround for that + API keys would be open to making it work, though there should probably still be a manual human approval for pointing to upstream versions since breaking API changes still happen with dawn.

BTW, besides the issues - if you want to bring things up with the dawn team they seem to frequent matrix chat https://app.element.io/#/room/#webgpu-dawn:matrix.org

@austinvhuang I investigated downloading the artifacts from the dawn CI. The API requires a token for this -- https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#download-an-artifact

we likely could set this up via CI though

https://github.com/marketplace/actions/download-workflow-artifact

This script hits the forbidden from lack of token
...

@austinvhuang
Copy link
Contributor

It seems like a good approach to fall back to downloading if not found. @austinvhuang how often do you think people will want to actually change and build their own dawnlib? We may be able to get by with downloads being the default or only support path for CMake?

Downloads as a default common case make sense to me. Building from dawn would be a nice-to-have (but not must-have) for power users - for example @junjihashimoto is investigating subgroup features that landed in dawn the dawn repo at head just a few days ago. Another reason it could come up is for environments that we don't have the bandwidth to provide prebuilt binaries for.

Ideally we could put that behind a flag (and/or as a fallback if downloads fail), but if it adds too much complexity we can consider leaving it out.

@austinvhuang
Copy link
Contributor

In this version the project will be installed to third_party/local/dawn/install. Maybe the next step is to move the libs and include files to their designated place.

Seems reasonable for now. In general, keeping cmake builds/locations coherent is good but mixing locations with the simplified make builds could be tricky since the generated include header is part of the repo and pinned to the prebuilt binary artifact version (so it's fine, maybe preferable, to keep those locations separate unless we have a strategy to make them play nice together).

@austinvhuang
Copy link
Contributor

Okay - going ahead and merging for now. Happy to explore further refinements (eg dawn artifacts) in separate PRs or in the discord chat. Thanks!

@austinvhuang austinvhuang merged commit e82dc40 into AnswerDotAI:main Aug 12, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants