diff --git a/.github/wasm-pages/coi-serviceworker.js b/.github/wasm-pages/coi-serviceworker.js
new file mode 100644
index 000000000..9901474cc
--- /dev/null
+++ b/.github/wasm-pages/coi-serviceworker.js
@@ -0,0 +1,146 @@
+/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
+let coepCredentialless = false;
+if (typeof window === 'undefined') {
+ self.addEventListener("install", () => self.skipWaiting());
+ self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim()));
+
+ self.addEventListener("message", (ev) => {
+ if (!ev.data) {
+ return;
+ } else if (ev.data.type === "deregister") {
+ self.registration
+ .unregister()
+ .then(() => {
+ return self.clients.matchAll();
+ })
+ .then(clients => {
+ clients.forEach((client) => client.navigate(client.url));
+ });
+ } else if (ev.data.type === "coepCredentialless") {
+ coepCredentialless = ev.data.value;
+ }
+ });
+
+ self.addEventListener("fetch", function (event) {
+ const r = event.request;
+ if (r.cache === "only-if-cached" && r.mode !== "same-origin") {
+ return;
+ }
+
+ const request = (coepCredentialless && r.mode === "no-cors")
+ ? new Request(r, {
+ credentials: "omit",
+ })
+ : r;
+ event.respondWith(
+ fetch(request)
+ .then((response) => {
+ if (response.status === 0) {
+ return response;
+ }
+
+ const newHeaders = new Headers(response.headers);
+ newHeaders.set("Cross-Origin-Embedder-Policy",
+ coepCredentialless ? "credentialless" : "require-corp"
+ );
+ if (!coepCredentialless) {
+ newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
+ }
+ newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");
+
+ return new Response(response.body, {
+ status: response.status,
+ statusText: response.statusText,
+ headers: newHeaders,
+ });
+ })
+ .catch((e) => console.error(e))
+ );
+ });
+
+} else {
+ (() => {
+ const reloadedBySelf = window.sessionStorage.getItem("coiReloadedBySelf");
+ window.sessionStorage.removeItem("coiReloadedBySelf");
+ const coepDegrading = (reloadedBySelf == "coepdegrade");
+
+ // You can customize the behavior of this script through a global `coi` variable.
+ const coi = {
+ shouldRegister: () => !reloadedBySelf,
+ shouldDeregister: () => false,
+ coepCredentialless: () => true,
+ coepDegrade: () => true,
+ doReload: () => window.location.reload(),
+ quiet: false,
+ ...window.coi
+ };
+
+ const n = navigator;
+ const controlling = n.serviceWorker && n.serviceWorker.controller;
+
+ // Record the failure if the page is served by serviceWorker.
+ if (controlling && !window.crossOriginIsolated) {
+ window.sessionStorage.setItem("coiCoepHasFailed", "true");
+ }
+ const coepHasFailed = window.sessionStorage.getItem("coiCoepHasFailed");
+
+ if (controlling) {
+ // Reload only on the first failure.
+ const reloadToDegrade = coi.coepDegrade() && !(
+ coepDegrading || window.crossOriginIsolated
+ );
+ n.serviceWorker.controller.postMessage({
+ type: "coepCredentialless",
+ value: (reloadToDegrade || coepHasFailed && coi.coepDegrade())
+ ? false
+ : coi.coepCredentialless(),
+ });
+ if (reloadToDegrade) {
+ !coi.quiet && console.log("Reloading page to degrade COEP.");
+ window.sessionStorage.setItem("coiReloadedBySelf", "coepdegrade");
+ coi.doReload("coepdegrade");
+ }
+
+ if (coi.shouldDeregister()) {
+ n.serviceWorker.controller.postMessage({ type: "deregister" });
+ }
+ }
+
+ // If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are
+ // already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here.
+ if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return;
+
+ if (!window.isSecureContext) {
+ !coi.quiet && console.log("COOP/COEP Service Worker not registered, a secure context is required.");
+ return;
+ }
+
+ // In some environments (e.g. Firefox private mode) this won't be available
+ if (!n.serviceWorker) {
+ !coi.quiet && console.error("COOP/COEP Service Worker not registered, perhaps due to private mode.");
+ return;
+ }
+
+ n.serviceWorker.register(window.document.currentScript.src).then(
+ (registration) => {
+ !coi.quiet && console.log("COOP/COEP Service Worker registered", registration.scope);
+
+ registration.addEventListener("updatefound", () => {
+ !coi.quiet && console.log("Reloading page to make use of updated COOP/COEP Service Worker.");
+ window.sessionStorage.setItem("coiReloadedBySelf", "updatefound");
+ coi.doReload();
+ });
+
+ // If the registration is active, but it's not controlling the page
+ if (registration.active && !n.serviceWorker.controller) {
+ !coi.quiet && console.log("Reloading page to make use of COOP/COEP Service Worker.");
+ window.sessionStorage.setItem("coiReloadedBySelf", "notcontrolling");
+ coi.doReload();
+ }
+ },
+ (err) => {
+ !coi.quiet && console.error("COOP/COEP Service Worker failed to register:", err);
+ }
+ );
+ })();
+}
diff --git a/.github/wasm-pages/index.html b/.github/wasm-pages/index.html
new file mode 100644
index 000000000..0cb63082d
--- /dev/null
+++ b/.github/wasm-pages/index.html
@@ -0,0 +1,70 @@
+
+
+
+
+ JANA2 WebAssembly
+
+
+
+
+
+ JANA2 WebAssembly + Dynamic Linking
+ This runs JANA2 natively in the browser with Web Workers (pthreads) and dynamically loads the JTest.so side module.
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/workflows/wasm-pages.yml b/.github/workflows/wasm-pages.yml
new file mode 100644
index 000000000..c601ee28d
--- /dev/null
+++ b/.github/workflows/wasm-pages.yml
@@ -0,0 +1,71 @@
+name: Deploy WASM Pages
+
+on:
+ push:
+ branches:
+ - wasm
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Emscripten
+ uses: mymindstorm/setup-emsdk@v14
+
+ - name: Configure CMake
+ run: |
+ emcmake cmake -B build -S . \
+ -DCMAKE_CXX_FLAGS="-pthread -sUSE_PTHREADS=1" \
+ -DCMAKE_C_FLAGS="-pthread -sUSE_PTHREADS=1" \
+ -DCMAKE_EXE_LINKER_FLAGS="-sEXPORTED_RUNTIME_METHODS=callMain,FS -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency -sPROXY_TO_PTHREAD=1" \
+ -DCMAKE_SHARED_LINKER_FLAGS="-pthread -sUSE_PTHREADS=1" \
+ -DCMAKE_MODULE_LINKER_FLAGS="-pthread -sUSE_PTHREADS=1" \
+ -DBUILD_SHARED_LIBS=ON
+
+ - name: Build jana and JTest
+ run: cmake --build build --target jana JTest -j4
+
+ - name: Prepare Pages Directory
+ run: |
+ mkdir -p dist
+ # Copy our HTML and ServiceWorker
+ cp .github/wasm-pages/index.html dist/
+ cp .github/wasm-pages/coi-serviceworker.js dist/
+
+ # Copy the WASM artifacts
+ cp build/src/programs/jana/jana.js dist/
+ cp build/src/programs/jana/jana.wasm dist/
+ cp build/src/programs/jana/jana.worker.js dist/ || true
+
+ cp build/lib/libJANA.so dist/ || cp build/src/libraries/JANA/libJANA.so dist/
+
+ # Copy the plugin side module
+ cp build/lib/JANA/plugins/JTest.so dist/ || cp build/src/plugins/JTest/JTest.so dist/
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: './dist'
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3aead24a6..3cbc53fcd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,19 @@ cmake_minimum_required(VERSION 3.16)
cmake_policy(SET CMP0074 NEW) # find_package() uses _ROOT implicit hints
project(jana2 VERSION 2026.03.01)
+include(GNUInstallDirs)
+if(EMSCRIPTEN)
+ set(CMAKE_INSTALL_BINDIR ".")
+ set(CMAKE_INSTALL_LIBDIR ".")
+endif()
+if(EMSCRIPTEN)
+ string(APPEND CMAKE_CXX_FLAGS " -fwasm-exceptions")
+ string(APPEND CMAKE_C_FLAGS " -fwasm-exceptions")
+ set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
+ string(APPEND CMAKE_EXE_LINKER_FLAGS " -sMAIN_MODULE=1 -sWASM_BIGINT=1 -fwasm-exceptions -sALLOW_MEMORY_GROWTH=1")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS " -sSIDE_MODULE=1 -sWASM_BIGINT=1 -fwasm-exceptions -sALLOW_MEMORY_GROWTH=1")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS " -sSIDE_MODULE=1 -sWASM_BIGINT=1 -fwasm-exceptions -sALLOW_MEMORY_GROWTH=1")
+endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Enable -fPIC for all targets
@@ -80,7 +93,7 @@ endif()
if (${USE_PODIO})
find_package(podio REQUIRED)
set(JANA2_HAVE_PODIO 1)
- set(USE_ROOT ON)
+ # set(USE_ROOT ON) # Disabled for WASM
include_directories(SYSTEM ${podio_INCLUDE_DIR})
else()
set(JANA2_HAVE_PODIO 0)
@@ -170,7 +183,7 @@ if (USE_PERFETTO)
$<$,$,$>:
-Wno-sign-compare -Wno-unused-parameter -Wno-missing-field-initializers>
)
- install(TARGETS perfetto_sdk EXPORT jana2_targets DESTINATION lib)
+ install(TARGETS perfetto_sdk EXPORT jana2_targets DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${PERFETTO_SDK_DIR}/perfetto.h DESTINATION include/perfetto)
set(JANA2_HAVE_PERFETTO 1)
else()
@@ -278,10 +291,10 @@ endif()
#---------------------------------------------------------------------------------------
-install(DIRECTORY scripts/ DESTINATION bin FILES_MATCHING PATTERN "jana-*.py"
+install(DIRECTORY scripts/ DESTINATION ${CMAKE_INSTALL_BINDIR} FILES_MATCHING PATTERN "jana-*.py"
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE)
- install(FILES "scripts/jana-status.sh" RENAME "jana-status" DESTINATION "bin"
+ install(FILES "scripts/jana-status.sh" RENAME "jana-status" DESTINATION "${CMAKE_INSTALL_BINDIR}"
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE)
include(${CMAKE_SOURCE_DIR}/cmake/MakeConfig.cmake)
diff --git a/cmake/AddJanaLibrary.cmake b/cmake/AddJanaLibrary.cmake
index e2667903c..1995289f0 100644
--- a/cmake/AddJanaLibrary.cmake
+++ b/cmake/AddJanaLibrary.cmake
@@ -86,7 +86,7 @@ macro(add_jana_library library_name)
install(TARGETS ${library_name}
EXPORT ${LIBRARY_EXPORT}
PUBLIC_HEADER DESTINATION include/${INSTALL_NAMESPACE}/${CWD_NAME}
- LIBRARY DESTINATION lib
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
# Handle tests
@@ -99,7 +99,7 @@ macro(add_jana_library library_name)
INSTALL_RPATH_USE_LINK_PATH TRUE
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib"
)
- #install(TARGETS ${library_name}_tests RUNTIME DESTINATION bin)
+ #install(TARGETS ${library_name}_tests RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
add_test(NAME ${library_name}_tests COMMAND ${library_name}_tests)
set_tests_properties(${library_name}_tests PROPERTIES
ENVIRONMENT "LD_LIBRARY_PATH=$:$:$ENV{LD_LIBRARY_PATH}"
diff --git a/cmake/AddJanaPlugin.cmake b/cmake/AddJanaPlugin.cmake
index f10e26448..da73038d3 100644
--- a/cmake/AddJanaPlugin.cmake
+++ b/cmake/AddJanaPlugin.cmake
@@ -60,6 +60,11 @@ macro(add_jana_plugin plugin_name)
endif()
# Set up target
+ if (EMSCRIPTEN)
+ set(JANA_INSTALL_PLUGINDIR ".")
+ else()
+ set(JANA_INSTALL_PLUGINDIR "${CMAKE_INSTALL_LIBDIR}/${INSTALL_NAMESPACE}/plugins")
+ endif()
add_library(${plugin_name} SHARED ${PLUGIN_SOURCES})
set_target_properties(${plugin_name} PROPERTIES
@@ -91,7 +96,7 @@ macro(add_jana_plugin plugin_name)
install(TARGETS ${plugin_name}
EXPORT ${PLUGIN_EXPORT}
PUBLIC_HEADER DESTINATION include/${INSTALL_NAMESPACE}/plugins/${plugin_name}
- LIBRARY DESTINATION lib/${INSTALL_NAMESPACE}/plugins
+ LIBRARY DESTINATION ${JANA_INSTALL_PLUGINDIR}
)
# Handle tests
@@ -104,7 +109,7 @@ macro(add_jana_plugin plugin_name)
INSTALL_RPATH_USE_LINK_PATH TRUE
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib;${CMAKE_INSTALL_PREFIX}/lib/${INSTALL_NAMESPACE}/plugins"
)
- #install(TARGETS ${plugin_name}-tests RUNTIME DESTINATION bin)
+ #install(TARGETS ${plugin_name}-tests RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
add_test(NAME ${plugin_name}-tests COMMAND ${plugin_name}-tests)
set_tests_properties(${plugin_name}-tests PROPERTIES
ENVIRONMENT "JANA_PLUGIN_PATH=${CMAKE_BINARY_DIR}/lib/JANA/plugins;LD_LIBRARY_PATH=$:$ENV{LD_LIBRARY_PATH}"
diff --git a/cmake/AddJanaTest.cmake b/cmake/AddJanaTest.cmake
index c62b646a8..0f83a6df5 100644
--- a/cmake/AddJanaTest.cmake
+++ b/cmake/AddJanaTest.cmake
@@ -33,7 +33,7 @@ macro(add_jana_test test_target_name)
INSTALL_RPATH_USE_LINK_PATH TRUE
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib;${CMAKE_INSTALL_PREFIX}/lib/JANA/plugins")
- install(TARGETS ${test_target_name} RUNTIME DESTINATION bin)
+ install(TARGETS ${test_target_name} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
add_test(NAME ${test_target_name} COMMAND ${test_target_name})
set_tests_properties(${test_target_name} PROPERTIES
diff --git a/cmake/MakeJanaThis.cmake b/cmake/MakeJanaThis.cmake
index 9335c34a9..809602508 100644
--- a/cmake/MakeJanaThis.cmake
+++ b/cmake/MakeJanaThis.cmake
@@ -148,6 +148,6 @@ configure_file(scripts/jana-config.in jana-config @ONLY)
configure_file(scripts/jana-this.sh.in jana-this.sh @ONLY)
configure_file(scripts/jana-this.csh.in jana-this.csh @ONLY)
-install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/jana-config DESTINATION bin)
-install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/jana-this.sh DESTINATION bin)
-install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/jana-this.csh DESTINATION bin)
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/jana-config DESTINATION ${CMAKE_INSTALL_BINDIR})
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/jana-this.sh DESTINATION ${CMAKE_INSTALL_BINDIR})
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/jana-this.csh DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/examples/misc/PodioDatamodel/CMakeLists.txt b/src/examples/misc/PodioDatamodel/CMakeLists.txt
index eb6bab7cf..1674e29b5 100644
--- a/src/examples/misc/PodioDatamodel/CMakeLists.txt
+++ b/src/examples/misc/PodioDatamodel/CMakeLists.txt
@@ -14,17 +14,17 @@ if (USE_PODIO)
install(TARGETS PodioDatamodel
EXPORT jana2_targets
- LIBRARY DESTINATION lib
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION include/JANA/examples/PodioDatamodel
)
install(TARGETS PodioDatamodelDict
EXPORT jana2_targets
- DESTINATION lib
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/PodioDatamodelDictDict.rootmap DESTINATION lib)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libPodioDatamodelDict_rdict.pcm DESTINATION lib)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/PodioDatamodelDictDict.rootmap DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libPodioDatamodelDict_rdict.pcm DESTINATION ${CMAKE_INSTALL_LIBDIR})
else()
message(STATUS "Skipping examples/PodioDatamodel because USE_PODIO=Off")
diff --git a/src/examples/misc/RootDatamodelExample/CMakeLists.txt b/src/examples/misc/RootDatamodelExample/CMakeLists.txt
index b69436391..862ee5466 100644
--- a/src/examples/misc/RootDatamodelExample/CMakeLists.txt
+++ b/src/examples/misc/RootDatamodelExample/CMakeLists.txt
@@ -41,7 +41,7 @@ if(${USE_ROOT})
target_link_libraries(RootDatamodelExample PUBLIC ROOT::Core)
message(STATUS "Installing ROOT PCM files: ${my_pcms}")
- install(FILES ${my_pcms} DESTINATION lib/JANA/plugins)
+ install(FILES ${my_pcms} DESTINATION ${JANA_INSTALL_PLUGINDIR})
add_test(NAME jana-example-rootdatamodel-tests
COMMAND $ -Pplugins=RootDatamodelExample -Pjana:nevents=10)
diff --git a/src/examples/misc/SubeventCUDAExample/CMakeLists.txt b/src/examples/misc/SubeventCUDAExample/CMakeLists.txt
index c3ee3f7e4..09c93689e 100644
--- a/src/examples/misc/SubeventCUDAExample/CMakeLists.txt
+++ b/src/examples/misc/SubeventCUDAExample/CMakeLists.txt
@@ -16,7 +16,7 @@ if (USE_CUDA)
OUTPUT_NAME "SubeventCUDAExample"
CUDA_ARCHITECTURES "75;80")
- install(TARGETS SubeventCUDAExample DESTINATION bin)
+ install(TARGETS SubeventCUDAExample DESTINATION ${CMAKE_INSTALL_BINDIR})
add_test(NAME jana-example-subevent-cuda-tests
COMMAND SubeventCUDAExample)
diff --git a/src/examples/misc/SubeventExample/CMakeLists.txt b/src/examples/misc/SubeventExample/CMakeLists.txt
index 351a260f9..a1d45e54c 100644
--- a/src/examples/misc/SubeventExample/CMakeLists.txt
+++ b/src/examples/misc/SubeventExample/CMakeLists.txt
@@ -3,7 +3,7 @@
add_executable(SubeventExample SubeventExample.cc)
target_link_libraries(SubeventExample jana2)
set_target_properties(SubeventExample PROPERTIES PREFIX "" OUTPUT_NAME "SubeventExample")
-install(TARGETS SubeventExample DESTINATION bin)
+install(TARGETS SubeventExample DESTINATION ${CMAKE_INSTALL_BINDIR})
add_test(NAME jana-example-subevent-tests
COMMAND SubeventExample)
diff --git a/src/examples/tutorial_with_lightweight_datamodel/19_wrapper_program/CMakeLists.txt b/src/examples/tutorial_with_lightweight_datamodel/19_wrapper_program/CMakeLists.txt
index ac74de407..b89c48fdf 100644
--- a/src/examples/tutorial_with_lightweight_datamodel/19_wrapper_program/CMakeLists.txt
+++ b/src/examples/tutorial_with_lightweight_datamodel/19_wrapper_program/CMakeLists.txt
@@ -9,5 +9,5 @@ target_link_libraries(lw-tutorial-recon PRIVATE
)
# Note that if you are outside the JANA2 source tree, you need to target_link_libraries against JANA::jana2_shared_lib instead
-install(TARGETS lw-tutorial-recon DESTINATION bin)
+install(TARGETS lw-tutorial-recon DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/examples/tutorial_with_podio_datamodel/01_datamodel/CMakeLists.txt b/src/examples/tutorial_with_podio_datamodel/01_datamodel/CMakeLists.txt
index 75a652376..5142c6c46 100644
--- a/src/examples/tutorial_with_podio_datamodel/01_datamodel/CMakeLists.txt
+++ b/src/examples/tutorial_with_podio_datamodel/01_datamodel/CMakeLists.txt
@@ -13,15 +13,15 @@ PODIO_ADD_ROOT_IO_DICT(jana2_tutorial_podio_datamodel_dict jana2_tutorial_podio_
install(TARGETS jana2_tutorial_podio_datamodel
EXPORT jana2_targets
- LIBRARY DESTINATION lib
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION include/jana2_tutorial_podio_datamodel
)
install(TARGETS jana2_tutorial_podio_datamodel_dict
EXPORT jana2_targets
- DESTINATION lib
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jana2_tutorial_podio_datamodel_dictDict.rootmap DESTINATION lib)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libjana2_tutorial_podio_datamodel_dict_rdict.pcm DESTINATION lib)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jana2_tutorial_podio_datamodel_dictDict.rootmap DESTINATION ${CMAKE_INSTALL_LIBDIR})
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libjana2_tutorial_podio_datamodel_dict_rdict.pcm DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/libraries/JANA/CLI/JBenchmarker.cc b/src/libraries/JANA/CLI/JBenchmarker.cc
index 46e59a7ce..0e8b92751 100644
--- a/src/libraries/JANA/CLI/JBenchmarker.cc
+++ b/src/libraries/JANA/CLI/JBenchmarker.cc
@@ -1,3 +1,6 @@
+#ifdef __EMSCRIPTEN__
+#include
+#endif
// Copyright 2020, Jefferson Science Associates, LLC.
// Subject to the terms in the LICENSE file found in the top-level directory.
@@ -192,6 +195,87 @@ void JBenchmarker::RunUntilFinished() {
// Hopefully, because we called flush(), the files will be partially filled even if we are SIGKILLed
// before we reach this point.
+#ifdef __EMSCRIPTEN__
+
+ MAIN_THREAD_EM_ASM({
+
+ var rates_path = UTF8ToString($0);
+
+ var samples_path = UTF8ToString($1);
+
+ if (typeof window !== "undefined" && typeof Blob !== "undefined") {
+
+ function triggerDownload(path) {
+
+ try {
+
+ var content = FS.readFile(path);
+
+ var blob = new Blob([content], { type: "application/octet-stream" });
+
+ var url = URL.createObjectURL(blob);
+
+ var a = document.createElement("a");
+
+ a.href = url;
+
+ var parts = path.split("/");
+
+ a.download = parts[parts.length - 1];
+
+ document.body.appendChild(a);
+
+ a.click();
+
+ document.body.removeChild(a);
+
+ URL.revokeObjectURL(url);
+
+ } catch(e) {
+
+ console.error("Failed to download " + path, e);
+
+ }
+
+ }
+
+ triggerDownload(rates_path);
+
+ setTimeout(function() { triggerDownload(samples_path); }, 500);
+
+ } else if (typeof ENVIRONMENT_IS_NODE !== "undefined" && ENVIRONMENT_IS_NODE) {
+
+ var fs = require("fs");
+
+ function copyOut(path) {
+
+ try {
+
+ var content = FS.readFile(path);
+
+ var parts = path.split("/");
+
+ fs.writeFileSync(parts[parts.length - 1], content);
+
+ } catch(e) {
+
+ console.error("Failed to extract " + path, e);
+
+ }
+
+ }
+
+ copyOut(rates_path);
+
+ copyOut(samples_path);
+
+ }
+
+ }, (m_output_dir + "/" + m_rates_filename).c_str(), (m_output_dir + "/" + m_samples_filename).c_str());
+
+#endif
+
+
samples_file.close();
rates_file.close();
diff --git a/src/libraries/JANA/CMakeLists.txt b/src/libraries/JANA/CMakeLists.txt
index e2e5a9fec..6a2824c33 100644
--- a/src/libraries/JANA/CMakeLists.txt
+++ b/src/libraries/JANA/CMakeLists.txt
@@ -83,7 +83,10 @@ if (USE_PERFETTO)
endif()
if (${USE_PODIO})
- target_link_libraries(jana2 PUBLIC podio::podio podio::podioRootIO)
+ target_link_libraries(jana2 PUBLIC podio::podio)
+ if(USE_ROOT)
+ target_link_libraries(jana2 PUBLIC podio::podioRootIO)
+ endif()
elseif (${USE_ROOT})
target_link_libraries(jana2 PUBLIC ROOT::Core)
endif()
@@ -102,11 +105,14 @@ if (USE_PERFETTO)
endif()
if (${USE_PODIO})
- target_link_libraries(jana2_static_lib PUBLIC podio::podio podio::podioRootIO)
+ target_link_libraries(jana2_static_lib PUBLIC podio::podio)
+ if(USE_ROOT)
+ target_link_libraries(jana2_static_lib PUBLIC podio::podioRootIO)
+ endif()
elseif (${USE_ROOT})
target_link_libraries(jana2_static_lib PUBLIC ROOT::Core)
endif()
-install(TARGETS jana2_static_lib EXPORT jana2_targets DESTINATION lib)
+install(TARGETS jana2_static_lib EXPORT jana2_targets DESTINATION ${CMAKE_INSTALL_LIBDIR})
# Build shared library
@@ -122,12 +128,15 @@ if (USE_PERFETTO)
endif()
if (${USE_PODIO})
- target_link_libraries(jana2_shared_lib PUBLIC podio::podio podio::podioRootIO)
+ target_link_libraries(jana2_shared_lib PUBLIC podio::podio)
+ if(USE_ROOT)
+ target_link_libraries(jana2_shared_lib PUBLIC podio::podioRootIO)
+ endif()
elseif (${USE_ROOT})
target_link_libraries(jana2_shared_lib PUBLIC ROOT::Core)
endif()
-install(TARGETS jana2_shared_lib EXPORT jana2_targets DESTINATION lib)
+install(TARGETS jana2_shared_lib EXPORT jana2_targets DESTINATION ${CMAKE_INSTALL_LIBDIR})
set(INSTALL_RPATH_USE_LINK_PATH True)
diff --git a/src/libraries/JANA/Engine/JExecutionEngine.cc b/src/libraries/JANA/Engine/JExecutionEngine.cc
index 60fd6a94e..382378136 100644
--- a/src/libraries/JANA/Engine/JExecutionEngine.cc
+++ b/src/libraries/JANA/Engine/JExecutionEngine.cc
@@ -324,7 +324,9 @@ void JExecutionEngine::HandleFailures() {
if (worker->is_timed_out) {
std::string arrow_name = (worker->last_arrow_id == static_cast(-1)) ? "(none)" : m_topology->GetArrows()[worker->last_arrow_id]->GetName();
LOG_FATAL(GetLogger()) << "Timeout in worker thread " << worker->worker_id << " while executing " << arrow_name << " on event #" << worker->last_event_nr << LOG_END;
+#ifndef __EMSCRIPTEN__
pthread_kill(worker->thread->native_handle(), SIGUSR2);
+#endif
LOG_INFO(GetLogger()) << "Worker thread signalled; waiting for backtrace capture." << LOG_END;
worker->backtrace.WaitForCapture();
}
@@ -821,7 +823,9 @@ void JExecutionEngine::PrintWorkerReport(bool send_to_pipe) {
LOG_INFO(GetLogger()) << "Generating worker report. It may take some time to retrieve each symbol's debug information." << LOG_END;
for (auto& worker: m_worker_states) {
worker->backtrace.Reset();
+#ifndef __EMSCRIPTEN__
pthread_kill(worker->thread->native_handle(), SIGUSR2);
+#endif
}
for (auto& worker: m_worker_states) {
worker->backtrace.WaitForCapture();
diff --git a/src/libraries/JANA/Services/JPluginLoader.cc b/src/libraries/JANA/Services/JPluginLoader.cc
index 568ec9839..7bbad871a 100644
--- a/src/libraries/JANA/Services/JPluginLoader.cc
+++ b/src/libraries/JANA/Services/JPluginLoader.cc
@@ -138,6 +138,10 @@ void JPluginLoader::attach_plugins(JComponentManager* jcm) {
// User didn't provide a path, so we have to search
// If no valid paths found, `path` variable stays empty
+#ifdef __EMSCRIPTEN__
+ if (path.empty()) path = name + ".so";
+#endif
+
if (path.empty()) {
LOG_ERROR(m_logger)
<< "Couldn't find plugin '" << name << "'\n"
diff --git a/src/libraries/JANA/Utils/JBacktrace.cc b/src/libraries/JANA/Utils/JBacktrace.cc
index 6ccbdb6e4..94550488e 100644
--- a/src/libraries/JANA/Utils/JBacktrace.cc
+++ b/src/libraries/JANA/Utils/JBacktrace.cc
@@ -5,6 +5,60 @@
#include "JBacktrace.h"
+#ifdef __EMSCRIPTEN__
+#include
+
+JBacktrace::JBacktrace(const JBacktrace& other) {
+ m_ready = other.m_ready.load();
+ m_frame_count = other.m_frame_count;
+ m_frames_to_omit = other.m_frames_to_omit;
+ m_buffer = other.m_buffer;
+}
+
+JBacktrace& JBacktrace::operator=(const JBacktrace& other) {
+ m_ready = other.m_ready.load();
+ m_frame_count = other.m_frame_count;
+ m_frames_to_omit = other.m_frames_to_omit;
+ m_buffer = other.m_buffer;
+ return *this;
+}
+
+JBacktrace::JBacktrace(JBacktrace&& other) {
+ m_ready = other.m_ready.load();
+ m_frame_count = other.m_frame_count;
+ m_frames_to_omit = other.m_frames_to_omit;
+ m_buffer = std::move(other.m_buffer);
+}
+
+void JBacktrace::Reset() {
+ m_ready = false;
+}
+
+void JBacktrace::WaitForCapture() const {
+}
+
+void JBacktrace::Capture(int frames_to_omit) {
+ m_frame_count = 0;
+ m_frames_to_omit = frames_to_omit;
+ m_ready.store(true, std::memory_order_release);
+}
+
+void JBacktrace::Format(std::ostream& os) const {
+ os << "Backtrace not supported on Emscripten." << std::endl;
+}
+
+std::string JBacktrace::AddrToLineInfo(const char* filename, size_t offset) const {
+ return "";
+}
+
+std::string JBacktrace::ToString() const {
+ std::ostringstream oss;
+ Format(oss);
+ return oss.str();
+}
+
+#else
+
#include
#include
#include
@@ -130,5 +184,6 @@ std::string JBacktrace::ToString() const {
return oss.str();
}
+#endif
diff --git a/src/libraries/JANA/Utils/JCpuInfo.cc b/src/libraries/JANA/Utils/JCpuInfo.cc
index 6bd72b432..b6d5248b3 100644
--- a/src/libraries/JANA/Utils/JCpuInfo.cc
+++ b/src/libraries/JANA/Utils/JCpuInfo.cc
@@ -68,6 +68,8 @@ uint32_t GetCpuID() {
#endif // __cpuid_count
return cpuid;
+#elif defined(__EMSCRIPTEN__)
+ return 0;
#else //__APPLE__
return sched_getcpu();
#endif //__APPLE__
@@ -75,7 +77,9 @@ uint32_t GetCpuID() {
bool PinThreadToCpu(std::thread* thread, size_t cpu_id) {
-
+#ifdef __EMSCRIPTEN__
+ return false;
+#else
if (typeid(std::thread::native_handle_type) != typeid(pthread_t)) {
return false;
}
@@ -99,6 +103,7 @@ bool PinThreadToCpu(std::thread* thread, size_t cpu_id) {
}
#endif
return true;
+#endif // __EMSCRIPTEN__
}
} // JCpuInfo namespace
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index f3db8d855..505e1f940 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -1,10 +1,12 @@
-
add_subdirectory(JTest)
add_subdirectory(janacontrol)
add_subdirectory(janadot)
add_subdirectory(janarate)
-add_subdirectory(janaroot)
-add_subdirectory(janaview)
+if(USE_ROOT)
+ add_subdirectory(janaroot)
+ if(TARGET ROOT::Gui)
+ add_subdirectory(janaview)
+ endif()
+endif()
add_subdirectory(regressiontest)
add_subdirectory(perfetto)
-
diff --git a/src/plugins/janaview/CMakeLists.txt b/src/plugins/janaview/CMakeLists.txt
index 9bc7ae051..21d56d2ab 100644
--- a/src/plugins/janaview/CMakeLists.txt
+++ b/src/plugins/janaview/CMakeLists.txt
@@ -12,8 +12,8 @@ if(USE_ROOT)
PUBLIC_HEADER ${JANAVIEW_HEADERS}
)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libjv_mainframe_rdict.pcm DESTINATION lib/JANA/plugins)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libjv_mainframe.rootmap DESTINATION lib/JANA/plugins)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libjv_mainframe_rdict.pcm DESTINATION ${JANA_INSTALL_PLUGINDIR})
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libjv_mainframe.rootmap DESTINATION ${JANA_INSTALL_PLUGINDIR})
else()
diff --git a/src/programs/jana/CMakeLists.txt b/src/programs/jana/CMakeLists.txt
index 9ed2f11ff..f7a80b36c 100644
--- a/src/programs/jana/CMakeLists.txt
+++ b/src/programs/jana/CMakeLists.txt
@@ -5,5 +5,12 @@ add_executable(jana jana.cc )
find_package(Threads REQUIRED)
target_link_libraries(jana jana2_shared_lib)
target_link_options(jana PRIVATE -rdynamic)
-install(TARGETS jana DESTINATION bin)
+install(TARGETS jana DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+
+if(EMSCRIPTEN)
+ target_link_options(jana PRIVATE "-sEXPORTED_RUNTIME_METHODS=callMain,FS")
+ install(FILES $/jana.wasm DESTINATION ${CMAKE_INSTALL_BINDIR})
+ install(FILES $/jana.worker.js DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL)
+endif()
diff --git a/src/programs/perf_tests/BasicTopology.cc b/src/programs/perf_tests/BasicTopology.cc
index c9e21a9aa..a7492a474 100644
--- a/src/programs/perf_tests/BasicTopology.cc
+++ b/src/programs/perf_tests/BasicTopology.cc
@@ -29,7 +29,7 @@ struct PESrc : public JEventSource {
data_out.SetShortName("1");
}
JEventSource::Result Emit(JEvent& event) override {
- data_out().push_back(new Data {event.GetEventNumber()*3 });
+ data_out().push_back(new Data {static_cast(event.GetEventNumber()*3) });
JBenchUtils::consume_cpu_us(*latency_us);
return Result::Success;
};
diff --git a/src/programs/perf_tests/SourceTopology.cc b/src/programs/perf_tests/SourceTopology.cc
index 63d603d49..1446de864 100644
--- a/src/programs/perf_tests/SourceTopology.cc
+++ b/src/programs/perf_tests/SourceTopology.cc
@@ -25,7 +25,7 @@ struct Src : public JEventSource {
data_out.SetShortName("1");
}
JEventSource::Result Emit(JEvent& block) override {
- data_out().push_back(new Data {block.GetEventNumber()*3 });
+ data_out().push_back(new Data {static_cast(block.GetEventNumber()*3) });
JBenchUtils::consume_cpu_us(*latency_us);
return Result::Success;
};
diff --git a/src/programs/perf_tests/TapChainTopology.cc b/src/programs/perf_tests/TapChainTopology.cc
index b38dc9363..ce879093f 100644
--- a/src/programs/perf_tests/TapChainTopology.cc
+++ b/src/programs/perf_tests/TapChainTopology.cc
@@ -25,7 +25,7 @@ struct Src : public JEventSource {
data_out.SetShortName("1");
}
JEventSource::Result Emit(JEvent& evt) override {
- data_out().push_back(new Data {evt.GetEventNumber()*3 });
+ data_out().push_back(new Data {static_cast(evt.GetEventNumber()*3) });
JBenchUtils::consume_cpu_us(*latency_us);
return Result::Success;
};
diff --git a/src/programs/perf_tests/UnfoldTopology.cc b/src/programs/perf_tests/UnfoldTopology.cc
index 918fc41e9..0cb886f97 100644
--- a/src/programs/perf_tests/UnfoldTopology.cc
+++ b/src/programs/perf_tests/UnfoldTopology.cc
@@ -27,7 +27,7 @@ struct BSrc : public JEventSource {
data_out.SetShortName("1");
}
JEventSource::Result Emit(JEvent& block) override {
- data_out().push_back(new Data {block.GetEventNumber()*3 });
+ data_out().push_back(new Data {static_cast(block.GetEventNumber()*3) });
JBenchUtils::consume_cpu_us(*latency_us);
return Result::Success;
};