Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6361e1b
add submodule for c api, library compilation with PackageCompiler
m-fila Nov 11, 2024
f867409
add ClusterSequence constants
m-fila Nov 11, 2024
7f41cdd
add writing jets selections results to ptr
m-fila Nov 12, 2024
237f7f0
add measuring execution time for c-app
m-fila Nov 14, 2024
dd5df39
add precompile execution, remove precompile statements, use args for …
m-fila Nov 14, 2024
0b90241
add cmake configuration
m-fila Nov 15, 2024
484ac86
fix format
m-fila Nov 18, 2024
34c2ba1
add example cmake downstream, add comments
m-fila Nov 18, 2024
f7b4029
update docstrings
m-fila Nov 19, 2024
0194ddf
remove obsolete files
m-fila Nov 19, 2024
e5b5047
add status codes
m-fila Nov 20, 2024
3e0e368
add missing header guard
m-fila Nov 20, 2024
797efa6
fix pointee lifetime in precompilation file
m-fila Nov 21, 2024
3d26983
add extern C when C++
m-fila Feb 10, 2025
6d21d72
cover more scenarios in precompile
m-fila Feb 10, 2025
2551e6d
fix C array length type
m-fila Feb 10, 2025
524551c
add tests for c-interface
m-fila Feb 10, 2025
8e48e7e
add test PseudoJet__init
m-fila Feb 10, 2025
c8961b6
add compiling with juliac
m-fila Mar 11, 2025
6f47257
update downstream example to work with juliac compiled lib
m-fila Mar 12, 2025
08a2c5b
update compile README
m-fila Mar 13, 2025
9fdf0dc
point to 1.12 nighthlies in the readme, remove compat on julia version
m-fila Mar 18, 2025
2c409bf
comment on minimal libstdc++ for julia 1.12
m-fila Mar 20, 2025
b85b990
update readme
m-fila Mar 24, 2025
6cff5c4
remove constrain on JetReconstruction version in compile project
m-fila Jun 27, 2025
8a108f2
add cluster history index argument to pseudojet init
m-fila Jul 2, 2025
4aad538
use batch memory operations
m-fila Jul 2, 2025
c33ff08
add recombination schemes to C-bindings
m-fila Jul 2, 2025
48d975d
update docs, fix typos, use workaround for Julia 1.10 docstrings for …
m-fila Jul 3, 2025
1292f1f
add downstream project gitignore
m-fila Jul 3, 2025
3c2481f
prevent breaking cmake substitution with clang-format
m-fila Jul 3, 2025
c16cdef
add support for GenKt
m-fila Jul 4, 2025
d15a8f2
update juliac location
m-fila Jul 14, 2025
7db31ad
adapt to changed jet selection signature
m-fila Jul 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ benchmark/*
**/profile/*
/statprof/*
/debug/*

# Compiled packages
JetReconstructionCompiled
10 changes: 10 additions & 0 deletions compile/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[deps]
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
JetReconstruction = "44e8cb2c-dfab-4825-9c70-d4808a591196"
PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d"

[sources]
JetReconstruction = {path = ".."}

[compat]
PackageCompiler = "2"
118 changes: 118 additions & 0 deletions compile/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Compiling JetReconstruction.jl to a C-library

Minimal C bindings for JetReconstruction.jl

- [C-header](include/JetReconstruction.h.in)
- shared library compiled with [PackageCompiler.jl](https://github.com/JuliaLang/PackageCompiler.jl) or juliac

## Building library

To build the library, run the following command from the package root directory:

```sh
julia --project=compile compile/build.jl --output-dir JetReconstructionCompiled
```

> [!NOTE]
> Since Julia 1.12 `--juliac` can be specified to use the juliac compiler instead of PackageCompiler.
> Before Julia 1.12, nightlies can be used instead (make sure to instantiate the main JetReconstruction and `compile` projects with the same version of Julia):
>
> ```sh
> julia +1.12-nightly --project=compile compile/build.jl --juliac
> ```
>
> or
>
> ```sh
> julia +nightly --project=compile compile/build.jl --juliac
> ```
>
> Packages compiled with `PackageCompiler.jl` will have `JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER` defined. Packages compiled with `juliac` will have `JETRECONSTRUCTION_COMPILER_JULIAC` defined.


> [!CAUTION]
> Packages compiled with Julia 1.12 require GLIBCXX_3.4.30 (gcc 12.1.0) or later.

## Usage example

### Example source file

Example usage of C bindings in an application:

```C
#include "JetReconstruction.h"

/*Should be automatically generated by PackageCompiler.jl and distributed together with the "JetReconstruction.h" header file*/
#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER
#include "julia_init.h"
#endif

int main(int argc, char *argv[]) {
#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER
init_julia(0, NULL); /*initialization of julia runtime*/
#endif

/*Prepare array of pseudo jets*/
size_t particles_len;
jetreconstruction_PseudoJet* particles;
/*Initialize with desired values*/

/*Call jet reconstruction*/
jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA;
double R = 3.0;
double power = 0.0;
jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST;
jetreconstruction_RecombinationScheme recombination = JETRECONCSTRUCTION_RECOMBINATIONSCHEME_ESCHEME;

jetreconstruction_ClusterSequence cluster_seq;
jetreconstruction_StatusCode sc = jetreconstruction_jet_reconstruct(particles, len, algorithm, power, R,
strategy, recombination, &cluster_seq);
if (sc != JETRECONSTRUCTION_STATUSCODE_OK){
/*An error occurred check the value or stderr for more information*/
return 1;
}

/*Use the cluster sequence in your application
then free memory allocations done by library*/
jetreconstruction_ClusterSequence_free_members(&cluster_seq);
#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER
shutdown_julia(0); /*teardown of julia runtime*/
#endif
return 0;
}

```

### Example compilation

To build an example application run the following command:

```shell
cc -o jetreconstruction_test compile/downstream/jetreconstruction_test.c -IJetReconstructionCompiled/include -LJetReconstructionCompiled/lib -ljetreconstruction
```

In case the compiled library resides in non-standard location, add its location to `LD_LIBRARY_PATH` when running example application:

```shell
LD_LIBRARY_PATH=JetReconstructionCompiled/lib/:${LD_LIBRARY_PATH} ./jetreconstruction_test
```

### Compilation with CMake

The JetReconstruction library comes with a CMake target `JetReconstruction::JetReconstruction`. Example usage in CMake file:

```cmake
find_package(JetReconstruction REQUIRED)

target_link_libraries(myTarget PUBLIC JetReconstruction::JetReconstruction)
```

## Limitations

Currently it's not possible to create libraries for different platforms - no cross-compilation!

PackageCompiler specific:

- The library is relocatable given the whole installation tree is moved, including libraries in the `lib/julia/` directory.
- It's advised to install the library in a separate directory to avoid possible conflicts.
The library must not be installed in the same directory as another Julia package compiled with `PackageCompiler.jl` as they would overwrite the package specific files in `share/julia`.
107 changes: 107 additions & 0 deletions compile/build.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using PackageCompiler
import ArgParse
import JetReconstruction

function parse_args(args)
s = ArgParse.ArgParseSettings()
ArgParse.@add_arg_table s begin
"--source-dir"
help = "Directory containing the source files"
arg_type = String
default = splitdir(@__DIR__) |> first

"--output-dir", "-o"
help = "Directory to save the compiled library"
arg_type = String
default = joinpath(splitdir(@__DIR__) |> first, "JetReconstructionCompiled")

"--juliac"
help = "Use juliac compiler"
action = :store_true
end

return ArgParse.parse_args(args, s)
end

function cp_file(input_dir, basename, output_dir)
cp(joinpath(input_dir, basename),
joinpath(output_dir, basename); force = true)
end

function configure_file(template_path::String, output_path::String,
replacements::Dict{String, String})
template = read(template_path, String)
for (key, value) in replacements
template = replace(template, "@$(key)@" => value)
end
open(output_path, "w") do io
write(io, template)
end
end

function compile_w_packagecompiler(source_dir, output_dir)
return @elapsed PackageCompiler.create_library(source_dir, output_dir;
lib_name = "jetreconstruction",
precompile_execution_file = [joinpath(@__DIR__,
"precompile_execution.jl")],
incremental = false,
filter_stdlibs = true,
force = true)
end

function compile_w_juliac(source_dir, output_dir)
julia_path = joinpath(Sys.BINDIR, Base.julia_exename())
juliac_path = joinpath(Sys.BINDIR, "..", "share", "julia", "juliac", "juliac.jl")
jetreconstruction_path = joinpath(source_dir, "src", "JetReconstruction.jl")
lib_dir = joinpath(output_dir, "lib")
mkpath(lib_dir)
output_lib = joinpath(lib_dir, "libjetreconstruction.so")
command = "$(julia_path) --project=$(source_dir) $(juliac_path) --experimental --trim=no --compile-ccallable --output-lib $(output_lib) $(jetreconstruction_path)"
@info command
return @elapsed run(`$(split(command))`)
end

function (@main)(args)
parsed_args = parse_args(args)
source_dir = parsed_args["source-dir"]
output_dir = parsed_args["output-dir"]

@info "Compiling package from $source_dir"
@info "Creating library in $output_dir"

compilation_time = if parsed_args["juliac"]
@info "Using juliac compiler"
compile_w_juliac(source_dir, output_dir)
else
@info "Using PackageCompiler compiler"
compile_w_packagecompiler(source_dir, output_dir)
end
@info "Compiled in $(compilation_time) seconds"
compiler = parsed_args["juliac"] ? "JETRECONSTRUCTION_COMPILER_JULIAC" :
"JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER"

includes_input = joinpath(@__DIR__, "include")
includes_output = joinpath(output_dir, "include")
mkpath(includes_output)
@info "Copying header files to $includes_output"
configure_file(joinpath(includes_input, "JetReconstruction.h.in"),
joinpath(includes_output, "JetReconstruction.h"),
Dict("JETRECONSTRUCTION_COMPILER" => compiler))

cmake_input = joinpath(@__DIR__, "cmake", "JetReconstruction")
cmake_output = joinpath(output_dir, "lib", "cmake", "JetReconstruction")
@info "Copying CMake files to $cmake_output"
mkpath(cmake_output)

version = pkgversion(JetReconstruction)
cmake_project_version = "$(version.major).$(version.minor).$(version.patch)"

configure_file(joinpath(cmake_input, "JetReconstructionConfig.cmake.in"),
joinpath(cmake_output, "JetReconstructionConfig.cmake"),
Dict("JETRECONSTRUCTION_COMPILER" => compiler))
configure_file(joinpath(cmake_input, "JetReconstructionConfigVersion.cmake.in"),
joinpath(cmake_output, "JetReconstructionConfigVersion.cmake"),
Dict("PROJECT_VERSION" => cmake_project_version))
cp_file(cmake_input, "JetReconstructionTargets.cmake", cmake_output)
return 0
end
44 changes: 44 additions & 0 deletions compile/cmake/JetReconstruction/JetReconstructionConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Config file for the JetReconstruction.jl package
# Manually adjusted from standard cmake generated config file

set(JETRECONSTRUCTION_COMPILER "@JETRECONSTRUCTION_COMPILER@")

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)

macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()

macro(check_required_components _NAME)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(NOT ${_NAME}_${comp}_FOUND)
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_NAME}_FOUND FALSE)
endif()
endif()
endforeach()
endmacro()

####################################################################################

# - Create relocatable paths to headers.
# NOTE: Do not strictly need paths as all usage requirements are encoded in
# the imported targets created later.
set_and_check(JetReconstruction_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")

if (${JETRECONSTRUCTION_COMPILER} STREQUAL "JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER")
# - Create path to installed read-only data files (e.g. yaml files)
set_and_check(JetReconstruction_DATA_DIR "${PACKAGE_PREFIX_DIR}/share/julia")
endif()

# - Include the targets file to create the imported targets that a client can
# link to (libraries) or execute (programs)
include("${CMAKE_CURRENT_LIST_DIR}/JetReconstructionTargets.cmake")

# print the default "Found:" message and check library location
include(FindPackageHandleStandardArgs)
get_property(TEST_JETRECONSTRUCTION_LIBRARY TARGET JetReconstruction::JetReconstruction PROPERTY LOCATION)
find_package_handle_standard_args(JetReconstruction DEFAULT_MSG CMAKE_CURRENT_LIST_FILE TEST_JETRECONSTRUCTION_LIBRARY)
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major version is the same as the current one.
# The variable CVF_VERSION must be set before calling configure_file().


set(PACKAGE_VERSION "@PROJECT_VERSION@")

if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()

if(PACKAGE_VERSION MATCHES "^([0-9]+)\\.")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
endif()
else()
set(CVF_VERSION_MAJOR ${PACKAGE_VERSION})
endif()

if(PACKAGE_FIND_VERSION_RANGE)
# both endpoints of the range must have the expected major version
math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1")
if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR)
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT)))
set(PACKAGE_VERSION_COMPATIBLE FALSE)
elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
else()
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()

if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
endif()


# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()

# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()
Loading
Loading