Skip to content

Commit 43ea5e4

Browse files
committed
Implement CPM based incremental WebVulkan WASM build system
0 parents  commit 43ea5e4

17 files changed

Lines changed: 1567 additions & 0 deletions

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/build/
2+
/build*/
3+
/.3rdparty/
4+
/out/
5+
.DS_Store

CMakeLists.txt

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
cmake_minimum_required(VERSION 4.2)
2+
3+
project(webvulkan_llvmpipe_wasm LANGUAGES NONE)
4+
5+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
6+
7+
if(NOT CMAKE_BUILD_TYPE)
8+
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
9+
endif()
10+
11+
option(WASM_AUTO_FETCH_TOOLS "Auto-download missing tools during configure" ON)
12+
option(WEBVULKAN_BUILD_TESTS "Build maintainer smoke tests" OFF)
13+
option(WEBVULKAN_ALLOW_DEP_UPDATES "Allow dependency git update during configure" OFF)
14+
set(WASM_EMSDK_VERSION "latest" CACHE STRING "emsdk version or tag")
15+
set(WASM_EMSDK_GIT_URL "https://github.com/emscripten-core/emsdk.git" CACHE STRING "emsdk git repository URL")
16+
set(WASM_EMSDK_GIT_REF "14c18b569f55138fe4963924162244251f454fb0" CACHE STRING "Pinned emsdk git ref")
17+
set(WEBVULKAN_THIRDPARTY_DIR "${PROJECT_SOURCE_DIR}/.3rdparty" CACHE PATH "Shared directory for fetched third-party sources")
18+
set(WEBVULKAN_THIRDPARTY_STATE_DIR "${WEBVULKAN_THIRDPARTY_DIR}/.state" CACHE PATH "State directory for fetched third-party metadata")
19+
set(WEBVULKAN_CPM_VERSION "0.40.2" CACHE STRING "CPM.cmake release version")
20+
set(WEBVULKAN_CPM_DIR "${WEBVULKAN_THIRDPARTY_DIR}/cpm" CACHE PATH "Directory where CPM.cmake is stored")
21+
set(WEBVULKAN_CPM_SOURCE_CACHE "${WEBVULKAN_THIRDPARTY_DIR}/cpm-cache" CACHE PATH "Shared CPM source cache")
22+
set(WEBVULKAN_BUILD_DIR "${PROJECT_BINARY_DIR}/_webvulkan" CACHE PATH "Per-build internal artifacts directory")
23+
set(WASM_EMSDK_DIR "${WEBVULKAN_THIRDPARTY_DIR}/emsdk" CACHE PATH "Path where emsdk is cloned")
24+
set(WASM_BUILD_DIR "${WEBVULKAN_BUILD_DIR}/wasm" CACHE PATH "WASM sub-build directory")
25+
set(WEBVULKAN_EMSCRIPTEN_TOOLCHAIN_FILE "${PROJECT_SOURCE_DIR}/cmake/toolchains/WebVulkanEmscripten.cmake" CACHE FILEPATH "Custom Emscripten toolchain file")
26+
set(MESA_SRC_DIR "${WEBVULKAN_THIRDPARTY_DIR}/mesa" CACHE PATH "Path where Mesa is cloned")
27+
set(MESA_GIT_URL "https://github.com/Devsh-Graphics-Programming/mesa.git" CACHE STRING "Mesa git repository URL")
28+
set(MESA_GIT_REF "fc73e2257d9c2b51f64c78eaaafe878a73951eb8" CACHE STRING "Pinned Mesa git ref")
29+
set(MESA_WASM_BUILD_DIR "${WEBVULKAN_BUILD_DIR}/mesa-wasm" CACHE PATH "Mesa WASM build directory")
30+
set(LLVM_SRC_DIR "${WEBVULKAN_THIRDPARTY_DIR}/llvm-project" CACHE PATH "Path where llvm-project is cloned")
31+
set(LLVM_HOST_BUILD_DIR "${WEBVULKAN_BUILD_DIR}/llvm-host-tools" CACHE PATH "LLVM host tools build directory")
32+
set(LLVM_WASM_BUILD_DIR "${WEBVULKAN_BUILD_DIR}/llvm-wasm" CACHE PATH "LLVM wasm build directory")
33+
set(LLVM_WASM_INSTALL_DIR "${WEBVULKAN_THIRDPARTY_DIR}/llvm-wasm-install" CACHE PATH "LLVM wasm install directory")
34+
set(LLVM_PROVIDER "source" CACHE STRING "LLVM provider: source, prebuilt, or system")
35+
set_property(CACHE LLVM_PROVIDER PROPERTY STRINGS source prebuilt system)
36+
set(LLVM_GIT_REF "afd4df07ab0262482829d4410a6bae9f2809d37b" CACHE STRING "Pinned LLVM git ref")
37+
if(LLVM_GIT_REF STREQUAL "ee9aeb4e05aa8edd2077b79f6712ea353ef5be77")
38+
set(LLVM_GIT_REF "afd4df07ab0262482829d4410a6bae9f2809d37b" CACHE STRING "Pinned LLVM git ref" FORCE)
39+
endif()
40+
set(LLVM_PREBUILT_URL "" CACHE STRING "URL to prebuilt LLVM wasm archive for LLVM_PROVIDER=prebuilt")
41+
set(LLVM_PREBUILT_SHA256 "" CACHE STRING "SHA256 for LLVM_PREBUILT_URL (optional)")
42+
43+
set(CPM_SOURCE_CACHE "${WEBVULKAN_CPM_SOURCE_CACHE}" CACHE PATH "CPM source cache path" FORCE)
44+
set(FETCHCONTENT_QUIET OFF)
45+
if(WEBVULKAN_ALLOW_DEP_UPDATES)
46+
set(_WEBVULKAN_FETCH_UPDATES_DISCONNECTED OFF)
47+
else()
48+
set(_WEBVULKAN_FETCH_UPDATES_DISCONNECTED ON)
49+
endif()
50+
set(FETCHCONTENT_UPDATES_DISCONNECTED ${_WEBVULKAN_FETCH_UPDATES_DISCONNECTED} CACHE BOOL "FetchContent update disconnected mode" FORCE)
51+
set(CPM_UPDATE_DISCONNECTED ${_WEBVULKAN_FETCH_UPDATES_DISCONNECTED} CACHE BOOL "CPM update disconnected mode" FORCE)
52+
include(cmake/BootstrapCpm.cmake)
53+
webvulkan_bootstrap_cpm()
54+
include(cmake/FetchWebVulkanSources.cmake)
55+
56+
include(cmake/BootstrapEmsdk.cmake)
57+
ensure_emsdk_ready(
58+
EMCC_OUT EMSDK_EMCC
59+
TOOLCHAIN_OUT EMSCRIPTEN_TOOLCHAIN
60+
EMSDK_ROOT_OUT EMSDK_ROOT
61+
)
62+
63+
webvulkan_fetch_git_source(webvulkan_mesa
64+
REPOSITORY "${MESA_GIT_URL}"
65+
TAG "${MESA_GIT_REF}"
66+
SOURCE_DIR "${MESA_SRC_DIR}"
67+
)
68+
69+
if(LLVM_PROVIDER STREQUAL "source")
70+
webvulkan_fetch_git_source(webvulkan_llvm
71+
REPOSITORY "https://github.com/llvm/llvm-project.git"
72+
TAG "${LLVM_GIT_REF}"
73+
SOURCE_DIR "${LLVM_SRC_DIR}"
74+
)
75+
endif()
76+
77+
message(STATUS "Using emcc: ${EMSDK_EMCC}")
78+
message(STATUS "Using Emscripten toolchain: ${WEBVULKAN_EMSCRIPTEN_TOOLCHAIN_FILE}")
79+
message(STATUS "Using LLVM provider: ${LLVM_PROVIDER}")
80+
81+
if(NOT CMAKE_INSTALL_LIBDIR)
82+
set(CMAKE_INSTALL_LIBDIR "lib" CACHE PATH "Object code libraries")
83+
endif()
84+
if(NOT CMAKE_INSTALL_INCLUDEDIR)
85+
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files")
86+
endif()
87+
include(GNUInstallDirs)
88+
include(CMakePackageConfigHelpers)
89+
90+
set(SUBBUILD_GENERATOR "${CMAKE_GENERATOR}")
91+
if(NOT SUBBUILD_GENERATOR)
92+
message(FATAL_ERROR "No CMake generator selected")
93+
endif()
94+
95+
set(WEBVULKAN_DRIVER_ARCHIVE "${MESA_WASM_BUILD_DIR}/libwebvulkan_driver.full.a")
96+
set(WEBVULKAN_LLVMPIPE_ARCHIVE "${MESA_WASM_BUILD_DIR}/src/gallium/drivers/llvmpipe/libllvmpipe.full.a")
97+
set(WEBVULKAN_LAVAPIPE_ARCHIVE "${MESA_WASM_BUILD_DIR}/src/gallium/frontends/lavapipe/liblavapipe_st.full.a")
98+
set(WEBVULKAN_LLVMPIPE_STAMP "${PROJECT_BINARY_DIR}/.webvulkan_llvmpipe.stamp")
99+
100+
add_custom_command(
101+
OUTPUT "${WEBVULKAN_LLVMPIPE_STAMP}"
102+
COMMAND
103+
"${CMAKE_COMMAND}"
104+
-DEMSDK_ROOT=${EMSDK_ROOT}
105+
-DMESA_SRC_DIR=${MESA_SRC_DIR}
106+
-DMESA_GIT_REF=${MESA_GIT_REF}
107+
-DMESA_BUILD_DIR=${MESA_WASM_BUILD_DIR}
108+
-DWEBVULKAN_EMSCRIPTEN_TOOLCHAIN_FILE=${WEBVULKAN_EMSCRIPTEN_TOOLCHAIN_FILE}
109+
-DWEBVULKAN_SUBBUILD_GENERATOR=${SUBBUILD_GENERATOR}
110+
-DLLVM_SRC_DIR=${LLVM_SRC_DIR}
111+
-DLLVM_HOST_BUILD_DIR=${LLVM_HOST_BUILD_DIR}
112+
-DLLVM_WASM_BUILD_DIR=${LLVM_WASM_BUILD_DIR}
113+
-DLLVM_WASM_INSTALL_DIR=${LLVM_WASM_INSTALL_DIR}
114+
-DLLVM_PROVIDER=${LLVM_PROVIDER}
115+
-DLLVM_GIT_REF=${LLVM_GIT_REF}
116+
-DLLVM_PREBUILT_URL=${LLVM_PREBUILT_URL}
117+
-DLLVM_PREBUILT_SHA256=${LLVM_PREBUILT_SHA256}
118+
-P "${PROJECT_SOURCE_DIR}/cmake/BuildMesaLlvmpipeWasm.cmake"
119+
COMMAND "${CMAKE_COMMAND}" -E touch "${WEBVULKAN_LLVMPIPE_STAMP}"
120+
DEPENDS "${PROJECT_SOURCE_DIR}/cmake/BuildMesaLlvmpipeWasm.cmake"
121+
USES_TERMINAL
122+
VERBATIM
123+
)
124+
125+
add_custom_command(
126+
OUTPUT "${WEBVULKAN_DRIVER_ARCHIVE}" "${WEBVULKAN_LLVMPIPE_ARCHIVE}" "${WEBVULKAN_LAVAPIPE_ARCHIVE}"
127+
COMMAND "${CMAKE_COMMAND}" -E echo "webvulkan driver archive is ready"
128+
DEPENDS "${WEBVULKAN_LLVMPIPE_STAMP}"
129+
VERBATIM
130+
)
131+
132+
add_custom_target(llvmpipe_wasm_spike DEPENDS "${WEBVULKAN_DRIVER_ARCHIVE}")
133+
add_custom_target(lavapipe_wasm_spike DEPENDS llvmpipe_wasm_spike)
134+
135+
add_library(webvulkan_llvmpipe_wasm INTERFACE)
136+
add_library(webvulkan::llvmpipe_wasm ALIAS webvulkan_llvmpipe_wasm)
137+
add_library(webvulkan::lavapipe_wasm ALIAS webvulkan_llvmpipe_wasm)
138+
139+
add_dependencies(webvulkan_llvmpipe_wasm llvmpipe_wasm_spike)
140+
141+
target_include_directories(webvulkan_llvmpipe_wasm INTERFACE
142+
"$<BUILD_INTERFACE:${MESA_SRC_DIR}/include>"
143+
"$<BUILD_INTERFACE:${MESA_SRC_DIR}/src>"
144+
"$<BUILD_INTERFACE:${LLVM_WASM_INSTALL_DIR}/include>"
145+
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/mesa>"
146+
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/mesa/src>"
147+
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/llvm>"
148+
)
149+
150+
target_link_libraries(webvulkan_llvmpipe_wasm INTERFACE
151+
"$<BUILD_INTERFACE:${WEBVULKAN_DRIVER_ARCHIVE}>"
152+
)
153+
154+
set(WEBVULKAN_PACKAGE_NAME "WebVulkanLlvmpipeWasm")
155+
set(WEBVULKAN_CONFIG_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${WEBVULKAN_PACKAGE_NAME}")
156+
set(WEBVULKAN_CONFIG_FILE "${PROJECT_BINARY_DIR}/${WEBVULKAN_PACKAGE_NAME}Config.cmake")
157+
set(WEBVULKAN_VERSION_FILE "${PROJECT_BINARY_DIR}/${WEBVULKAN_PACKAGE_NAME}ConfigVersion.cmake")
158+
159+
configure_package_config_file(
160+
"${PROJECT_SOURCE_DIR}/cmake/${WEBVULKAN_PACKAGE_NAME}Config.cmake.in"
161+
"${WEBVULKAN_CONFIG_FILE}"
162+
INSTALL_DESTINATION "${WEBVULKAN_CONFIG_DIR}"
163+
PATH_VARS CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_INCLUDEDIR
164+
NO_SET_AND_CHECK_MACRO
165+
NO_CHECK_REQUIRED_COMPONENTS_MACRO
166+
)
167+
168+
write_basic_package_version_file(
169+
"${WEBVULKAN_VERSION_FILE}"
170+
VERSION "0.1.0"
171+
COMPATIBILITY SameMajorVersion
172+
)
173+
174+
install(CODE
175+
"if(NOT EXISTS \"${WEBVULKAN_LLVMPIPE_ARCHIVE}\" OR NOT EXISTS \"${WEBVULKAN_LAVAPIPE_ARCHIVE}\" OR NOT EXISTS \"${WEBVULKAN_DRIVER_ARCHIVE}\")\n message(FATAL_ERROR \"Build artifacts are missing. Run: cmake --build <build-dir> --target llvmpipe_wasm_spike\")\nendif()"
176+
)
177+
178+
install(FILES "${WEBVULKAN_LLVMPIPE_ARCHIVE}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" RENAME "libllvmpipe.a")
179+
install(FILES "${WEBVULKAN_LAVAPIPE_ARCHIVE}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" RENAME "liblavapipe_st.a")
180+
install(FILES "${WEBVULKAN_DRIVER_ARCHIVE}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" RENAME "libwebvulkan_driver.a")
181+
install(DIRECTORY "${MESA_SRC_DIR}/include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/mesa")
182+
install(DIRECTORY "${MESA_SRC_DIR}/src/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/mesa/src")
183+
install(DIRECTORY "${LLVM_WASM_INSTALL_DIR}/include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/llvm")
184+
install(FILES "${WEBVULKAN_CONFIG_FILE}" "${WEBVULKAN_VERSION_FILE}" DESTINATION "${WEBVULKAN_CONFIG_DIR}")
185+
186+
if(WEBVULKAN_BUILD_TESTS)
187+
add_subdirectory(tests)
188+
endif()

README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# WebVulkan - llvmpipe compiled to WASM
2+
3+
This repository provides a CMake-consumable WebAssembly build of Mesa llvmpipe/lavapipe.
4+
5+
Public link targets:
6+
7+
- `webvulkan::llvmpipe_wasm`
8+
- `webvulkan::lavapipe_wasm` (alias)
9+
10+
## Use from source (`add_subdirectory`)
11+
12+
```cmake
13+
add_subdirectory(path/to/llvmpipe2wasm)
14+
15+
add_executable(my_app src/main.c)
16+
target_link_libraries(my_app PRIVATE webvulkan::llvmpipe_wasm)
17+
```
18+
19+
Configure/build:
20+
21+
```powershell
22+
cmake -S . -B build -G Ninja
23+
cmake --build build
24+
```
25+
26+
## Use as relocatable package (`find_package`)
27+
28+
Build and install:
29+
30+
```powershell
31+
cmake -S . -B build -G Ninja
32+
cmake --build build
33+
cmake --install build --prefix <install-prefix>
34+
```
35+
36+
`cmake --install` expects build artifacts to already exist and does not trigger a build.
37+
38+
Consume:
39+
40+
```cmake
41+
find_package(WebVulkanLlvmpipeWasm REQUIRED CONFIG)
42+
43+
add_executable(my_app src/main.c)
44+
target_link_libraries(my_app PRIVATE webvulkan::llvmpipe_wasm)
45+
```

cmake/BootstrapCpm.cmake

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
include_guard(GLOBAL)
2+
3+
function(webvulkan_bootstrap_cpm)
4+
if(COMMAND CPMAddPackage)
5+
return()
6+
endif()
7+
8+
if(NOT DEFINED WEBVULKAN_CPM_VERSION OR WEBVULKAN_CPM_VERSION STREQUAL "")
9+
set(WEBVULKAN_CPM_VERSION "0.40.2")
10+
endif()
11+
if(NOT DEFINED WEBVULKAN_CPM_DIR OR WEBVULKAN_CPM_DIR STREQUAL "")
12+
set(WEBVULKAN_CPM_DIR "${CMAKE_CURRENT_LIST_DIR}/../.3rdparty/cpm")
13+
endif()
14+
15+
file(MAKE_DIRECTORY "${WEBVULKAN_CPM_DIR}")
16+
17+
set(CPM_FILE "${WEBVULKAN_CPM_DIR}/CPM_${WEBVULKAN_CPM_VERSION}.cmake")
18+
set(CPM_URL "https://github.com/cpm-cmake/CPM.cmake/releases/download/v${WEBVULKAN_CPM_VERSION}/CPM.cmake")
19+
20+
if(NOT EXISTS "${CPM_FILE}")
21+
message(STATUS "Downloading CPM.cmake v${WEBVULKAN_CPM_VERSION}")
22+
file(DOWNLOAD "${CPM_URL}" "${CPM_FILE}" STATUS CPM_DOWNLOAD_STATUS TLS_VERIFY ON)
23+
list(GET CPM_DOWNLOAD_STATUS 0 CPM_DOWNLOAD_CODE)
24+
if(NOT CPM_DOWNLOAD_CODE EQUAL 0)
25+
list(GET CPM_DOWNLOAD_STATUS 1 CPM_DOWNLOAD_MESSAGE)
26+
file(REMOVE "${CPM_FILE}")
27+
message(FATAL_ERROR "Failed to download CPM.cmake from ${CPM_URL}: ${CPM_DOWNLOAD_MESSAGE}")
28+
endif()
29+
endif()
30+
31+
include("${CPM_FILE}")
32+
endfunction()

0 commit comments

Comments
 (0)