Skip to content

Commit 01c8443

Browse files
committed
Merge remote-tracking branch 'origin/master' into issue/31-spectra-io-out-of-fortran
2 parents ef7c3dc + 0dcd0f5 commit 01c8443

36 files changed

+2149
-17035
lines changed

.github/workflows/pip.yml

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# From https://github.com/wjakob/nanobind_example/blob/5ce5ce57143a469e92d9ebaee9c47949ee77caa8/.github/workflows/pip.yml
2+
name: Pip
3+
4+
on:
5+
workflow_dispatch:
6+
pull_request:
7+
push:
8+
branches:
9+
- master
10+
11+
jobs:
12+
build:
13+
name: Build with Pip
14+
runs-on: ${{ matrix.platform }}
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
platform: [windows-latest, macos-latest, ubuntu-latest]
19+
#python-version: ["3.9", "3.12"]
20+
python-version: ["3.12"]
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: actions/setup-python@v5
26+
with:
27+
python-version: ${{ matrix.python-version }}
28+
29+
- name: Set min macOS version
30+
if: runner.os == 'macOS'
31+
run: |
32+
echo "MACOSX_DEPLOYMENT_TARGET=10.14" >> $GITHUB_ENV
33+
34+
- name: Build and install
35+
run: |
36+
python -m pip install pytest
37+
pip install --verbose ./bindings/python
38+
39+
- name: Test
40+
run: python -m unittest discover ./bindings/python/tests

.github/workflows/wheels.yml

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# From https://github.com/wjakob/nanobind_example/blob/5ce5ce57143a469e92d9ebaee9c47949ee77caa8/.github/workflows/wheels.yml
2+
3+
name: Wheels
4+
5+
on:
6+
workflow_dispatch:
7+
pull_request:
8+
push:
9+
branches:
10+
- master
11+
release:
12+
types:
13+
- published
14+
15+
jobs:
16+
build_sdist:
17+
name: Build SDist
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v4
21+
with:
22+
submodules: true
23+
24+
- name: Build SDist
25+
run: pipx run build --sdist ./bindings/python
26+
27+
- name: Check metadata
28+
run: pipx run twine check ./bindings/python/dist/*
29+
30+
- uses: actions/upload-artifact@v4
31+
with:
32+
name: dist-sdist
33+
path: dist/*.tar.gz
34+
35+
36+
build_wheels:
37+
name: Wheels on ${{ matrix.os }}
38+
runs-on: ${{ matrix.os }}
39+
strategy:
40+
fail-fast: false
41+
matrix:
42+
os: [ubuntu-latest, macos-13, macos-14, macos-latest, windows-latest]
43+
44+
steps:
45+
- uses: actions/checkout@v4
46+
with:
47+
submodules: true
48+
49+
- uses: pypa/[email protected]
50+
env:
51+
CIBW_ARCHS_MACOS: "universal2"
52+
with:
53+
package-dir: ./bindings/python
54+
55+
- name: Verify clean directory
56+
run: git diff --exit-code
57+
shell: bash
58+
59+
- name: Upload wheels
60+
uses: actions/upload-artifact@v4
61+
with:
62+
path: wheelhouse/*.whl
63+
name: dist-${{ matrix.os }}
64+
65+
upload_all:
66+
name: Upload if release
67+
needs: [build_wheels, build_sdist]
68+
runs-on: ubuntu-latest
69+
environment:
70+
name: pypi
71+
url: https://pypi.org/p/SandiaSpecUtils
72+
permissions:
73+
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
74+
if: github.event_name == 'release' && github.event.action == 'published'
75+
76+
steps:
77+
- uses: actions/setup-python@v5
78+
- uses: actions/download-artifact@v4
79+
with:
80+
pattern: dist-*
81+
merge-multiple: true
82+
- shell: bash
83+
run: |
84+
pwd
85+
ls
86+
87+
- uses: pypa/gh-action-pypi-publish@release/v1
88+
with:
89+
packages-dir: /home/runner/work/SpecUtils/SpecUtils
90+
user: __token__
91+
password: ${{ secrets.pypi_password }}

CMakeLists.txt

+6-39
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ option( SpecUtils_BUILD_UNIT_TESTS "Builds unit tests" OFF )
2020
option( SpecUtils_BUILD_FUZZING_TESTS "Builds fuzzing tests, requires clang" OFF )
2121
option( SpecUtils_BUILD_REGRESSION_TEST "Creates executable to perform interactive regression test" OFF )
2222
option( SpecUtils_BUILD_EXAMPLE "Builds example SpecUtil applications" OFF )
23-
option( SpecUtils_PYTHON_BINDINGS "Creates python bindings to the c++ code" OFF )
2423
option( SpecUtils_JAVA_SWIG "Creates swig/java bindings to the c++ code" OFF )
2524
option( SpecUtils_FORTRAN_SWIG "Enables build/test of swig/FORTRAN bindings" OFF )
2625
option( SpecUtils_FORTRAN_SWIG_GEN "When this is on, cmake will attemp to generate swig fortran bindings.
@@ -30,15 +29,7 @@ option( SpecUtils_INJA_TEMPLATES "Creates inja template interface" OFF )
3029
option( SpecUtils_USE_SIMD "Use SIMD operations; i386/x64 only right now, and very alpha, and extremely minimally used" OFF )
3130
option( SpecUtils_ENABLE_EQUALITY_CHECKS "Enables the equal_enough(...) functions for comparing two spectrum files." OFF ) #code size is only reason to default to off, I think
3231
option( PERFORM_DEVELOPER_CHECKS "Performs additional computationally expensive tests during execution (requires linking to boost)" OFF )
33-
34-
35-
if( SpecUtils_PYTHON_BINDINGS )
36-
option( SpecUtils_SHARED_LIB "Whether to compile a shared, or static library" ON )
37-
list( APPEND sources bindings/python/SpecFile_py.cpp )
38-
else()
39-
#default to building a static lib
40-
option( SpecUtils_SHARED_LIB "Whether to compile a shared, or static library" OFF )
41-
endif()
32+
option( SpecUtils_SHARED_LIB "Whether to compile a shared, or static library" OFF )
4233

4334

4435
set( SpecUtils_FLT_PARSE_METHOD "default_value" CACHE STRING [[How to parse lists of numbers.
@@ -86,7 +77,7 @@ endif()
8677

8778

8879
# If we are building this on Windows, not as a sub-project, lets enable selecting C++ runtime
89-
if( MSVC )
80+
if( MSVC AND SpecUtils_BUILD_UNIT_TESTS )
9081
get_directory_property(hasParent PARENT_DIRECTORY)
9182
if(NOT hasParent)
9283
option(${PROJECT_NAME}_USE_MSVC_MultiThreadDLL "Use dynamically-link runtime library." OFF)
@@ -100,7 +91,7 @@ if( MSVC )
10091
endif()
10192
message(STATUS "Using CMAKE_MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY}")
10293
endif(NOT hasParent)
103-
endif( MSVC )
94+
endif( MSVC AND SpecUtils_BUILD_UNIT_TESTS )
10495

10596

10697
if( SpecUtils_BUILD_EXAMPLE )
@@ -125,14 +116,6 @@ endif( SpecUtils_JAVA_SWIG )
125116

126117
set( THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty" )
127118

128-
if( SpecUtils_PYTHON_BINDINGS )
129-
FIND_PACKAGE(Python3 COMPONENTS Development )
130-
IF(NOT Python3_FOUND)
131-
MESSAGE(FATAL_ERROR "Unable to find PythonLibs.")
132-
ENDIF()
133-
message( "Python include dirs: ${Python3_INCLUDE_DIRS}")
134-
endif()
135-
136119
set( sources
137120
src/SpecFile.cpp
138121
src/SpecFile_pcf.cpp
@@ -259,10 +242,6 @@ if( SpecUtils_ENABLE_URI_SPECTRA )
259242
find_package( ZLIB REQUIRED )
260243
endif( SpecUtils_ENABLE_URI_SPECTRA )
261244

262-
if( SpecUtils_PYTHON_BINDINGS )
263-
list( APPEND sources bindings/python/SpecFile_py.cpp )
264-
endif( SpecUtils_PYTHON_BINDINGS )
265-
266245
if( SpecUtils_JAVA_SWIG )
267246
list( APPEND sources bindings/swig/SpecUtils.i )
268247
endif( SpecUtils_JAVA_SWIG )
@@ -351,28 +330,22 @@ if( SpecUtils_USE_FAST_FLOAT )
351330
endif( NOT FAST_FLOAT_FILE_PATH )
352331
endif( SpecUtils_USE_FAST_FLOAT )
353332

354-
# We only need boost libraries if we are using boost to parse floats, if we are performing developer
355-
# checks, or we are creating Python bindings
356-
if( SpecUtils_USE_BOOST_SPIRIT OR PERFORM_DEVELOPER_CHECKS OR SpecUtils_PYTHON_BINDINGS )
333+
# We only need boost libraries if we are using boost to parse floats, if we are performing developer checks
334+
if( SpecUtils_USE_BOOST_SPIRIT OR PERFORM_DEVELOPER_CHECKS )
357335

358336
if( DEFINED boost_SOURCE_DIR )
359337
# We used CMake Fetch to get boost (e.g., in InterSpec)
360338
target_link_libraries( SpecUtils PUBLIC Boost::system Boost::spirit Boost::fusion Boost::algorithm Boost::functional Boost::crc )
361339

362340
else( DEFINED boost_SOURCE_DIR )
363-
364-
if( SpecUtils_PYTHON_BINDINGS )
365-
list( APPEND boost_libs_required python )
366-
endif( SpecUtils_PYTHON_BINDINGS )
367-
368341
find_package( Boost REQUIRED COMPONENTS system ${boost_libs_required} )
369342
if( NOT Boost_FOUND )
370343
message(FATAL_ERROR "Couldnt Find Boost")
371344
endif( NOT Boost_FOUND )
372345

373346
target_link_libraries( SpecUtils PUBLIC Boost::system )
374347
endif( DEFINED boost_SOURCE_DIR )
375-
endif( SpecUtils_USE_BOOST_SPIRIT OR PERFORM_DEVELOPER_CHECKS OR SpecUtils_PYTHON_BINDINGS )
348+
endif( SpecUtils_USE_BOOST_SPIRIT OR PERFORM_DEVELOPER_CHECKS )
376349

377350
if( SpecUtils_USE_FROM_CHARS )
378351
if( NOT (MSVC AND (MSVC_VERSION GREATER_EQUAL 1920)) )
@@ -418,17 +391,11 @@ elseif( NOT SpecUtils_USING_NO_THREADING )
418391
endif( SpecUtils_USE_WT_THREADPOOL )
419392

420393

421-
422394
if( SpecUtils_ENABLE_URI_SPECTRA )
423395
target_link_libraries( SpecUtils PUBLIC ZLIB::ZLIB )
424396
endif( SpecUtils_ENABLE_URI_SPECTRA )
425397

426398

427-
if( SpecUtils_PYTHON_BINDINGS )
428-
target_link_libraries( SpecUtils PUBLIC Boost::python ${Boost_PYTHON_LIBRARY} ${Python3_LIBRARIES} )
429-
endif( SpecUtils_PYTHON_BINDINGS )
430-
431-
432399
if( SpecUtils_JAVA_SWIG )
433400
target_link_libraries( SpecUtils PUBLIC ${JAVA_LIBRARIES} )
434401
endif( SpecUtils_JAVA_SWIG )

SpecUtils/EnergyCalibration.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ namespace SpecUtils
279279
280280
Values larger than this will cause an exception to be thrown when setting the calibration.
281281
*/
282-
static const size_t sm_max_channels; // = 65536 + 8
282+
static const size_t sm_max_channels; // 131072 (previous to 20241112, used 65536 + 8)
283283

284284
/** The largest positive value of the offset (zeroth energy cal term) allowed for normal polynomial energy calibration.
285285
i.e., if a gamma spectrum has a larger value than this, then the calibration coefficients will be considered garbage and not used.

SpecUtils/StringAlgo.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,11 @@ namespace SpecUtils
224224
size_t utf8_str_size_limit( const char * const str,
225225
size_t num_in_bytes, const size_t max_bytes );
226226

227-
227+
/** Returns if the passed-in string is valid UTF-8.
228+
@param str The string to evaluate.
229+
@param num_in_bytes The length of the string - must not include (optional) null-terminator.
230+
*/
231+
bool valid_utf8( const char * const str, const size_t num_in_bytes );
228232

229233

230234
/** \brief parses a string of ascii characters to their floating point value.

bindings/python/CMakeLists.txt

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
cmake_minimum_required(VERSION 3.15...3.26)
2+
3+
project(SpecUtils_py LANGUAGES CXX)
4+
5+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
6+
7+
set( SpecUtils_ENABLE_D3_CHART ON CACHE BOOL "" )
8+
set( SpecUtils_D3_SUPPORT_FILE_STATIC ON CACHE BOOL "" )
9+
set( SpecUtils_ENABLE_URI_SPECTRA OFF CACHE BOOL "" ) #Lets not worry about linking to zlib right now
10+
set( SpecUtils_PYTHON_BINDINGS ON CACHE BOOL "Build the python bindings" )
11+
set( SpecUtils_ENABLE_EQUALITY_CHECKS OFF CACHE BOOL "" )
12+
set( PERFORM_DEVELOPER_CHECKS OFF CACHE BOOL "" )
13+
set( SpecUtils_SHARED_LIB OFF CACHE BOOL "" ) #we'll statically link SpecUtils into the lib we create here
14+
set( SpecUtils_FLT_PARSE_METHOD "strtod" CACHE STRING "Float parsing method" )
15+
16+
add_subdirectory( ${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR}/LibSpecUtils )
17+
18+
if (NOT SKBUILD)
19+
message(FATAL_ERROR "\
20+
This CMake file is must be executed using 'scikit-build'.
21+
If you are a user trying to install this package, please use the command
22+
below, which will install all necessary build dependencies, compile
23+
the package in an isolated environment, and then install it.
24+
=====================================================================
25+
$ pip install .
26+
=====================================================================
27+
If you are a software developer, and this is your own package, then
28+
it is usually much more efficient to install the build dependencies
29+
in your environment once and use the following command that avoids
30+
a costly creation of a new virtual environment at every compilation:
31+
=====================================================================
32+
$ pip install nanobind scikit-build-core
33+
$ pip install --no-build-isolation -ve .
34+
=====================================================================
35+
You may optionally add -Ceditable.rebuild=true to auto-rebuild when
36+
the package is imported. Otherwise, you need to re-run the above
37+
after editing C++ files.")
38+
endif()
39+
40+
# Try to import all Python components potentially needed by nanobind
41+
find_package(Python 3.8
42+
REQUIRED COMPONENTS Interpreter Development.Module
43+
OPTIONAL_COMPONENTS Development.SABIModule)
44+
45+
# Import nanobind through CMake's find_package mechanism
46+
find_package(nanobind CONFIG REQUIRED)
47+
48+
# We are now ready to compile the actual extension module
49+
nanobind_add_module(
50+
# Name of the extension
51+
PySpecUtils
52+
53+
# Target the stable ABI for Python 3.12+, which reduces
54+
# the number of binary wheels that must be built. This
55+
# does nothing on older Python versions
56+
STABLE_ABI
57+
58+
# Build libnanobind statically and merge it into the
59+
# extension (which itself remains a shared library)
60+
#
61+
# If your project builds multiple extensions, you can
62+
# replace this flag by NB_SHARED to conserve space by
63+
# reusing a shared libnanobind across libraries
64+
NB_STATIC
65+
66+
#Perform link time optimization.
67+
#LTO
68+
69+
70+
# Source code goes here
71+
SpecFile_py.cpp
72+
)
73+
74+
set_target_properties( PySpecUtils PROPERTIES OUTPUT_NAME "SpecUtils" )
75+
target_link_libraries( PySpecUtils PUBLIC SpecUtils )
76+
77+
# Install directive for scikit-build-core
78+
install(TARGETS PySpecUtils LIBRARY DESTINATION SpecUtils)
79+
install(FILES __init__.py DESTINATION SpecUtils)
80+
81+
nanobind_add_stub(
82+
SpecUtils_stub
83+
MODULE SpecUtils
84+
OUTPUT SpecUtils.pyi
85+
PYTHON_PATH $<TARGET_FILE_DIR:PySpecUtils>
86+
DEPENDS PySpecUtils
87+
)

bindings/python/Ex_pyconverted.chn

-64.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)