Skip to content

Commit f063cc3

Browse files
committed
Merge branch 'pr-40'
2 parents faff2d3 + 7fbf6b1 commit f063cc3

File tree

5 files changed

+70
-57
lines changed

5 files changed

+70
-57
lines changed

CMakeLists.txt

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,12 @@ option( SpecUtils_BUILD_UNIT_TESTS "Builds unit tests" OFF )
1919
option( SpecUtils_BUILD_FUZZING_TESTS "Builds fuzzing tests, requires clang" OFF )
2020
option( SpecUtils_BUILD_REGRESSION_TEST "Creates executable to perform interactive regression test" OFF )
2121
option( SpecUtils_BUILD_EXAMPLE "Builds example SpecUtil applications" OFF )
22-
option( SpecUtils_JAVA_SWIG "Creates swig/java bindings to the c++ code" OFF )
23-
option( SpecUtils_C_BINDINGS "Creates C bindings to the c++ code" OFF )
2422
option( SpecUtils_INJA_TEMPLATES "Creates inja template interface" OFF )
2523
option( SpecUtils_USE_SIMD "Use SIMD operations; i386/x64 only right now, and very alpha, and extremely minimally used" OFF )
2624
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
2725
option( PERFORM_DEVELOPER_CHECKS "Performs additional computationally expensive tests during execution (requires linking to boost)" OFF )
2826
option( SpecUtils_SHARED_LIB "Whether to compile a shared, or static library" OFF )
27+
option( SpecUtils_C_BINDINGS "Creates C bindings to the c++ code" OFF )
2928

3029

3130
set( SpecUtils_FLT_PARSE_METHOD "default_value" CACHE STRING [[How to parse lists of numbers.
@@ -94,30 +93,6 @@ if( SpecUtils_BUILD_EXAMPLE )
9493
add_subdirectory( examples )
9594
endif( SpecUtils_BUILD_EXAMPLE )
9695

97-
if( SpecUtils_JAVA_SWIG )
98-
#INCLUDE_DIRECTORIES("/opt/homebrew/opt/openjdk/include" )
99-
#INCLUDE_DIRECTORIES("/opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home/include/darwin/")
100-
#set(JAVA_AWT_LIBRARY "$ENV{JAVA_HOME}/lib/libjawt.so")
101-
#set(JAVA_JVM_LIBRARY "$ENV{JAVA_HOME}/lib/server/libjvm.so")
102-
#set(JAVA_INCLUDE_PATH "$ENV{JAVA_HOME}/include")
103-
#set(JAVA_INCLUDE_PATH2 "$ENV{JAVA_HOME}/include/linux")
104-
#set(JAVA_AWT_INCLUDE_PATH "$ENV{JAVA_HOME}/include")
105-
106-
FIND_PACKAGE( SWIG REQUIRED )
107-
FIND_PACKAGE( JNI REQUIRED )
108-
INCLUDE( ${SWIG_USE_FILE} )
109-
INCLUDE_DIRECTORIES( ${JAVA_INCLUDE_PATH} )
110-
INCLUDE_DIRECTORIES( ${JAVA_INCLUDE_PATH}/linux )
111-
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/bindings/swig )
112-
SET( CMAKE_SWIG_FLAGS -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_CURRENT_BINARY_DIR} -DSpecUtils_JAVA_SWIG=1 -package gov.sandia.specutils )
113-
SET( CMAKE_SWIG_OUTDIR gov/sandia/specutils )
114-
SET_SOURCE_FILES_PROPERTIES(bindings/swig/SpecUtils.i PROPERTIES CPLUSPLUS ON)
115-
SET_SOURCE_FILES_PROPERTIES(bindings/swig/SpecUtils.i PROPERTIES SWIG_FLAGS "")
116-
SWIG_ADD_MODULE( SpecUtilsJni java bindings/swig/SpecUtils.i )
117-
#SWIG_LINK_LIBRARIES( SpecUtilsJni ${JAVA_LIBRARIES} SpecUtils )
118-
swig_link_libraries(SpecUtilsJni SpecUtils)
119-
endif( SpecUtils_JAVA_SWIG )
120-
12196

12297
set( THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty" )
12398

@@ -247,9 +222,7 @@ if( SpecUtils_ENABLE_URI_SPECTRA )
247222
find_package( ZLIB REQUIRED )
248223
endif( SpecUtils_ENABLE_URI_SPECTRA )
249224

250-
if( SpecUtils_JAVA_SWIG )
251-
list( APPEND sources bindings/swig/SpecUtils.i )
252-
endif( SpecUtils_JAVA_SWIG )
225+
253226

254227
if( SpecUtils_C_BINDINGS )
255228
list( APPEND headers bindings/c/SpecUtils_c.h )
@@ -262,11 +235,14 @@ else( SpecUtils_SHARED_LIB )
262235
set( SpecUtils_LIB_TYPE STATIC )
263236
endif( SpecUtils_SHARED_LIB )
264237

238+
265239
add_library( SpecUtils ${SpecUtils_LIB_TYPE} ${sources} ${headers} ${OTHER_SUPPORT_FILES} )
266240
set_target_properties( SpecUtils PROPERTIES PREFIX "lib" OUTPUT_NAME "SpecUtils" )
267241

242+
set_property( TARGET SpecUtils PROPERTY POSITION_INDEPENDENT_CODE ON )
243+
268244
set( SpecUtils_USE_FAST_FLOAT OFF ) # Uses https://github.com/fastfloat/fast_float . If fast_float.h isnt found, will be fetched
269-
set( SpecUtils_USE_FROM_CHARS OFF ) # Supported by MSVC >= 2019, and gcc >= 12. Not supported by Apple clang. In MSVC, about 50% slower than boost::spirit
245+
set( SpecUtils_USE_FROM_CHARS OFF ) # Supported by MSVC >= 2019, and gcc >= 12. Only supported by Apple if targeting macOS 10.15 or newer. In MSVC, about 50% slower than boost::spirit
270246
set( SpecUtils_USE_BOOST_SPIRIT OFF ) # Uses boost::spirit, and fasted method (maybe a hair faster than fastfloat)
271247
set( SpecUtils_USE_STRTOD OFF ) # Slowest method, but works
272248

@@ -341,7 +317,7 @@ endif( SpecUtils_USE_BOOST_SPIRIT OR PERFORM_DEVELOPER_CHECKS )
341317

342318
if( SpecUtils_USE_FROM_CHARS )
343319
if( NOT (MSVC AND (MSVC_VERSION GREATER_EQUAL 1920)) )
344-
# MSVC >=2019 supports floating point from_chars, while Xcode 14 still doesnt (havent checked Android Studio)
320+
# MSVC >=2019 supports floating point from_chars, while for macOS you need to target macOS 10.15 or later
345321
message("Please double check your compiler does actually support std::from_chars for parsing floats")
346322
endif()
347323

@@ -388,10 +364,6 @@ if( SpecUtils_ENABLE_URI_SPECTRA )
388364
endif( SpecUtils_ENABLE_URI_SPECTRA )
389365

390366

391-
if( SpecUtils_JAVA_SWIG )
392-
target_link_libraries( SpecUtils PUBLIC ${JAVA_LIBRARIES} )
393-
endif( SpecUtils_JAVA_SWIG )
394-
395367

396368
if( MINGW )
397369
target_link_libraries( SpecUtils PUBLIC -static-libgcc -static libshlwapi.a libpthread.a libstdc++.a libwinpthread.a libmsvcrt.a )

README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,21 @@ int main() {
4848
### Relevant CMake Build options
4949
* **SpecUtils_ENABLE_D3_CHART** [default ON]: Enabling this feature allows exporting specta to a [D3.js](https://d3js.org/) based plotting that allows viewing and interacting with the spectra in a web browser. An example can be seen [here](examples/d3_chart_example/self_contained_example.html).
5050
* **SpecUtils_D3_SUPPORT_FILE_STATIC** [default ON]: Only relevant if *SpecUtils_ENABLE_D3_CHART* is *ON*. This option determines if all the JavaScript (including D3.js, SpectrumChartD3.js, etc) and CSS should be compiled into the library, or remain as seperate files accessed at runtime.
51-
* **SpecUtils_PYTHON_BINDINGS** [default OFF]: Determines if the Python bindings should be built. [Boost.Python](https://www.boost.org/doc/libs/1_69_0/libs/python/doc/html/index.html) is used to generate the bindings. Have a look in [test_python.py](bindings/python/test_python.py) for example use of **SpecUtils** from python.
52-
* **SpecUtils_JAVA_SWIG** [default OFF]: Determines if the Java bindings should be built. [SWIG](https://www.swig.org/) is used to generate the bindings, and an example application using them is in [bindings/swig/java_example/](bindings/swig/java_example/) directory.
53-
* **PERFORM_DEVELOPER_CHECKS** [default OFF]: Performs additional tests during program execution, with failed tests being output to a log file.
51+
* **SpecUtils_ENABLE_URI_SPECTRA** [default OFF]: Adds support for [URI-based-spectra](https://sandialabs.github.io/InterSpec/tutorials/references/spectrum_in_a_qr_code_uur_latest.pdf), such as you might find in QR-codes. Requires linking against zlib.
52+
* **SpecUtils_FLT_PARSE_METHOD** : How to parse floating point numbers from text files; options are `FastFloat`, `FromChars`, `boost`, `strtod`. `Boost` is the fastest method (but requires having boost installed), with `strtod` the slowest but most widely supported.
53+
* **PERFORM_DEVELOPER_CHECKS** [default OFF]: Performs additional tests during program execution, with failed tests being output to a log file; you normally want these off because they can be slow. Turning this option on also requires linking to `boost`.
54+
* **SpecUtils_SHARED_LIB** [default OFF]: Whether to compile a shared library, or static library.
55+
56+
## Bindings to other languages
57+
`SpecUtils` has explicit bindings to `Python`, `Java`, `Node`, and `C`, with the `C` known to be used from `C`, `Fortran`, and `Rust`.
58+
59+
To one of these bindings:
60+
* `Python`: The [nanobind](https://github.com/wjakob/nanobind) library is used to create these binding. To use a pre-compiled version via `pip`, see https://pypi.org/project/SandiaSpecUtils/ . If you would like to compile the bindings yourself, see [bindings/python/README.md](bindings/python/README.md). Some example uses are available in [bindings/python/examples](bindings/python/examples).
61+
* `Node`: The [node-addon-api](https://www.npmjs.com/package/node-addon-api) and [cmake-js](https://www.npmjs.com/package/cmake-js) packages are used to create these bindings; see [bindings/node/README.md](bindings/node/README.md) for instructions on compiling. An example use is in [example.js](bindings/node/example.js).
62+
* `Java`: The [SWIG](https://www.swig.org) package is used to create these bindings, and could likely be used for other languages. See [bindings/swig/README.md](bindings/swig/README.md) for compilation instructions. An example use of `SpecUtils` from java is included in the bindings directory.
63+
* `C`: These bindings are hand-written, and can be included when building `SpecUtils` by specifying the `SpecUtils_C_BINDINGS` CMake option to `ON`. There is an example use of C interface in [examples/c_interface_example.c](c_interface_example.c).
64+
65+
5466

5567
## Features
5668
* Parses >100 spectrum file format variants.
@@ -64,12 +76,13 @@ int main() {
6476
* Tools to help rebin, re-calibrate, truncate, and combine spectra.
6577
* And more!
6678

79+
6780
## Testing
6881
This library uses a few methods to test the code, but unfortunately still likely contains bugs or issues, especially related to specific file format variants.
6982

7083
The testing methods are:
7184
* Peppered throughout the code there are `#if( PERFORM_DEVELOPER_CHECKS )` statements that perform additional tests at runtime that make sure the correct answer was computed or action taken. Most of these blocks of code will either recompute a quantity using an independent implementation, or in someway perform additional sanity checks, and when issues are found, they are logged to a file for fixing in the future. This seems to work well as the primary developer of this library uses the library heavily.
72-
* An assortment of unit tests have been created and are occasionally run, but by no means offer anywhere near 100% coverage. Since many of the test contain proprietary data, they are not all distributed with the library.
85+
* An assortment of unit tests are avaiable in [unit_tests](unit_tests) and are ran as part of the CI/CD, but do not offer 100% coverage.
7386
* As the primary developer of this library comes across new file formats, or new variants of file formats, they get added to a library after manually verifying they are parsed sufficiently well. Then [regression_test/regression_test.cpp](regression_test/regression_test.cpp) is used to ensure the files continue to be parsed exactly the same as when they were manually verified. Any changes to the information extracted from these files will then be manually verified to be an improvement to the parsing (like adding the ability to extract GPS coordinates from a format), or the issue will be corrected. This helps keep regressions from occurring. A keystone piece to this testing is that all information extracted from any file format can be written out to a N42-2012 file; when this N42-2012 file is read back in, the exact same information is available as from the original file (this property is of course also tested for).
7487
* [Fuzz testing](fuzz_test/) is periodically performed.
7588
* Near daily use to parse a wide variety of formats by the primary developer, as well as use by users of the applications built against SpecUtils.

bindings/node/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ project( SpecUtilsJS )
66
# cmake-js --CDSpecUtils_FLT_PARSE_METHOD="strtod" --CDCMAKE_BUILD_TYPE="Release"
77
# cmake-js build --target install
88

9-
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
9+
cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR)
1010

1111
set( CMAKE_CXX_STANDARD 11 )
1212
set( CMAKE_CXX_STANDARD_REQUIRED ON )

bindings/node/README.md

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,10 @@ In order to use **SpecUtils** from **node.js**, we need to compile the C++ into
77
To create the add-on we use [cmake-js](https://www.npmjs.com/package/cmake-js) to build the [SpecUtils](https://github.com/sandialabs/SpecUtils) library as well as some [node-addon-api](https://www.npmjs.com/package/node-addon-api) interface code to allow accessing the C++ functions from JavaScript. Once the module is built, it should work with any **node.js** versions >=6.14.2 thanks to the ABI stability offered by [n-api](https://nodejs.org/api/n-api.html).
88

99
## Prerequisites
10-
You will need a reasonable recent version of [CMake](https://cmake.org/) (version >=3.1) installed, a C++ compiler that can handle C++11, and the [boost](https://www.boost.org/) libraries (developed against 1.65.1 version shouldn't matter much) to link against. You will of course also need [node.js](https://nodejs.org/en/) installed.
11-
- **Windows**: You will need the CMake and node executables in your **PATH** variable. When installing node.js there may be an option to install the MSVC command line tools through Chocolatey, otherwise you will need to have MSVS-2012 or newer installed (development done with MSVS-2017). Other compilers (clang, [MingGW](https://nuwen.net/mingw.html)) *should* work, but have not been tested. This project links against the static runtime libraries (e.g., uses the '/MT' flag), and statically links to boost, so the resulting module is self contained. When executing the steps below to compile the code you will need to open the 'x64 Native Tools Command Prompt' provided by MSVS, or execute the appropriate *vcvarsall.bat*.
12-
- Instructions for building boost can be found [here](https://www.boost.org/doc/libs/1_65_1/more/getting_started/windows.html), but basically you want to do something like:
13-
```bash
14-
cd Path\To\boost_1_65_1
15-
boostrap.bat
16-
b2.exe -j4 runtime-link=static link=static threading=multi address-model=64 --prefix=C:\install\msvc2017\x64\boost_1_65_1 install
17-
```
18-
- **macOS**: You will need the Xcode command line tools installed, which can be done by running `xcode-select --install`. CMake, node, and boost can all be installed using [MacPorts](https://www.macports.org/), [HomeBrew](https://brew.sh/), or manually installed. Keep in mind it is best to statically link to boost (e.g., have the ".a" libraries availble).
19-
- **Linux**: You can use your package manager to install node.js, CMake, and the C++ compiler and related tools (usually with something like `apt-get install build-essential`). However, for boost some care may be needed. The `SpecUtils` module is really a shared library that node.js loads. To avoid dependencies we will statically link to the boost libraries (e.g., copy the needed boost code into the resulting SpecUtils.module file), meaning you need the `-fPIC` C/C++ compiler flag enabled not just for building `SpecUtils` code, but for all of the static libraries you link it against, namely, boost - which isn't the default when compiling static libraries. Therefore when building boost you may need to add `-fPIC -std=c++11` to the compile flags.
10+
You will need a reasonable recent version of [CMake](https://cmake.org/) (version >=3.5) installed, a C++ compiler that can handle C++11. You will of course also need [node.js](https://nodejs.org/en/) installed.
11+
- **Windows**: You will need the CMake and node executables in your **PATH** variable. When installing node.js there may be an option to install the MSVC command line tools through Chocolatey, otherwise you will need to have MSVS-2012 or newer installed (development done with MSVS-2017). Other compilers (clang, [MingGW](https://nuwen.net/mingw.html)) *should* work, but have not been tested. This project links against the static runtime libraries (e.g., uses the '/MT' flag) so the resulting module is self contained. When executing the steps below to compile the code you will need to open the 'x64 Native Tools Command Prompt' provided by MSVS, or execute the appropriate *vcvarsall.bat*.
12+
- **macOS**: You will need the Xcode command line tools installed, which can be done by running `xcode-select --install`. CMake, and node, which can be installed using [MacPorts](https://www.macports.org/), [HomeBrew](https://brew.sh/), or manually.
13+
- **Linux**: You can use your package manager to install node.js, CMake, and the C++ compiler and related tools (usually with something like `apt-get install build-essential`). However, for boost some care may be needed. The `SpecUtils` module is really a shared library that node.js loads.
2014

2115
# Build Instructions
2216
From bash or the Windows Command Prompt, run:
@@ -25,14 +19,14 @@ From bash or the Windows Command Prompt, run:
2519
npm install -g cmake-js
2620

2721
# For macOS only, you may want to define a deployment target
28-
export MACOSX_DEPLOYMENT_TARGET=10.10
22+
export MACOSX_DEPLOYMENT_TARGET=10.15
2923

3024
cd /path/to/SpecUtils/bindings/node/
3125

3226
# Install dependency for compiling a node.js add-on
3327
npm install --save-dev node-addon-api
3428

35-
# If boost is in a standard location, you can just run
29+
# To build int the "build" directory, with default
3630
cmake-js --CDSpecUtils_FLT_PARSE_METHOD="strtod"
3731

3832
# Note that the 'SpecUtils_FLT_PARSE_METHOD' options are "FastFloat", "FromChars",

bindings/swig/README.md

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,50 @@
1+
# Prerequisites
2+
3+
You need the Java JDK and Swig packages installed and in your environment variables.
4+
5+
On macOS, using Homebrew, you could install these with commands like:
6+
7+
```bash
8+
brew update
9+
brew upgrade
10+
brew install swig
11+
brew install openjdk
12+
13+
# Set the needed environment variables:
14+
export JAVA_HOME=$(brew --prefix openjdk)
15+
export PATH="$JAVA_HOME/bin:$PATH"
16+
17+
# And/or add to your .zshrc file for the future
18+
echo 'export JAVA_HOME=$(brew --prefix openjdk)' >> ~/.zshrc
19+
echo 'export PATH="$JAVA_HOME/bin:$PATH"' >> ~/.zshrc
20+
21+
# Test JDK is installed
22+
javac -version
23+
```
24+
125

226
To compile with support for Java use the following commands:
327
```bash
4-
cd SpecUtils
28+
cd SpecUtils/bindings/swig
529
mkdir build
630
cd build
7-
cmake -DSpecUtils_JAVA_SWIG=ON ..
8-
make -j4
31+
32+
# Configure the project with CMake
33+
cmake ..
34+
35+
# If the configuration failed with issues finding the Java stuff, you can
36+
# either edit the CMakeLists.txt file and hardcode some commented out path lines,
37+
# or prefferably, explicitly specify the java paths to cmake, like:
38+
cmake -DJAVA_INCLUDE_PATH=".../include" -DJAVA_JVM_LIBRARY=".../libjvm.dylib" ..
39+
40+
make -j8
941
```
1042

11-
To then run the example Java executable, do:
43+
All the .java files will then be in `gov/sandia/specutils`
44+
45+
To run the example Java executable, you can:
1246
```bash
13-
cp ../bindings/swig/java_example/* .
47+
cp ../java_example/* .
1448
javac -classpath .:jcommon-1.0.21.jar:jfreechart-1.0.17.jar:joda-time-2.9.jar *.java gov/sandia/specutils/*.java
1549
java -Djava.library.path="." -classpath .:jcommon-1.0.21.jar:jfreechart-1.0.17.jar:joda-time-2.9.jar Main
1650
```

0 commit comments

Comments
 (0)