diff --git a/CMakeLists.txt b/CMakeLists.txt index 1283064d..80857c51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,6 +246,9 @@ set(COOLPROP_ENABLED_BACKENDS # Get everything in the src/ directory (always), but not recursive file(GLOB APP_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +# Add the miniz source file +list(APPEND APP_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/externals/miniz-3.0.2/miniz.c") + # For each enabled backend, grab its files foreach(backend ${COOLPROP_ENABLED_BACKENDS}) file(GLOB_RECURSE BACKEND_SOURCES @@ -265,6 +268,12 @@ set(APP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") list(APPEND APP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/externals/Eigen") list(APPEND APP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/externals/msgpack-c/include") +list(APPEND APP_INCLUDE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}/externals/miniz-3.0.2") +list(APPEND APP_INCLUDE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}/externals/incbin") +list(APPEND APP_INCLUDE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}/dev") list(APPEND APP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/boost_CoolProp") list(APPEND APP_INCLUDE_DIRS @@ -1840,6 +1849,7 @@ if(COOLPROP_JAVASCRIPT_MODULE) endif() add_definitions(-sDISABLE_EXCEPTION_CATCHING=0) + add_definitions(-DCOOLPROP_NO_INCBIN) # # If you want a monolithic file with no async memory loading, define EMSCRIPTEN_NO_MEMORY_INIT_FILE # if(EMSCRIPTEN_NO_MEMORY_INIT_FILE) # set(EMSCRIPTEN_INIT_FLAG "--memory-init-file 0") diff --git a/dev/.gitignore b/dev/.gitignore new file mode 100644 index 00000000..d7a45280 --- /dev/null +++ b/dev/.gitignore @@ -0,0 +1 @@ +.*depcache diff --git a/dev/generate_headers.py b/dev/generate_headers.py index e925eb7f..546dcbfe 100644 --- a/dev/generate_headers.py +++ b/dev/generate_headers.py @@ -14,6 +14,7 @@ import struct import glob from pathlib import Path import pickle +import zlib json_options = {'indent': 2, 'sort_keys': True} @@ -50,6 +51,27 @@ values = [ ('pcsaft/all_pcsaft_fluids.json', 'all_pcsaft_JSON.h', 'all_pcsaft_JSON'), ('pcsaft/mixture_binary_pairs_pcsaft.json', 'mixture_binary_pairs_pcsaft_JSON.h', 'mixture_binary_pairs_pcsaft_JSON') ] +zvalues = [ + ('all_fluids.json.z', 'all_fluids_JSON_z.h', 'all_fluids_JSON_z'), +] + +incbin_template = r"""/* File generated for use with incbin */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* INCBIN(%SYMBOL%, "all_fluids.json.z"); */ +INCBIN_CONST INCBIN_ALIGN unsigned char g%SYMBOL%Data[] = { +%DATA% +}; +INCBIN_CONST INCBIN_ALIGN unsigned char *const g%SYMBOL%End = g%SYMBOL%Data + sizeof(g%SYMBOL%Data); +INCBIN_CONST unsigned int g%SYMBOL%Size = sizeof(g%SYMBOL%Data); + +#ifdef __cplusplus +} +#endif +""" def TO_CPP(root_dir, hashes): @@ -67,7 +89,46 @@ def TO_CPP(root_dir, hashes): def needs_build(inpath: Path, outpath: Path): if not outpath.exists(): return True + if not inpath.exists(): + raise ValueError(f"{inpath} cannot be found") return os.path.getmtime(inpath) > os.path.getmtime(outpath) + + for infile, outfile, variable in zvalues: + inpath = Path(root_dir) / 'dev' / infile + outpath = Path(root_dir) / 'include' / outfile + if not needs_build(inpath=inpath, outpath=outpath): + print(f'{outpath} is up to date based on file times') + continue + + json_ = inpath.open('rb').read() + + # convert each character to hex and add a terminating NULL character to end the + # string, join into a comma separated string + + try: + h = ["0x{:02x}".format(ord(b)) for b in json_] + ['0x00'] + except TypeError: + h = ["0x{:02x}".format(int(b)) for b in json_] + ['0x00'] + + # Break up the file into lines of 16 hex characters + chunks = to_chunks(h, 16) + + # Put the lines back together again + # The chunks are joined together with commas, and then EOL are used to join the rest + hex_string = ',\n'.join([', '.join(chunk) for chunk in chunks]) + + # Check if hash is up to date based on using variable as key + if not os.path.isfile(os.path.join(root_dir, 'include', outfile)) or variable not in hashes or (variable in hashes and hashes[variable] != get_hash(hex_string.encode('ascii'))): + + with (Path(root_dir) / 'include' / outfile).open('w') as fp: + fp.write(incbin_template.replace('%SYMBOL%', variable).replace('%DATA%', hex_string)) + + # Store the hash of the data that was written to file (not including the header) + hashes[variable] = get_hash(hex_string.encode('ascii')) + + print(os.path.join(root_dir, 'include', outfile) + ' written to file') + else: + print(outfile + ' is up to date') for infile, outfile, variable in values: inpath = Path(root_dir) / 'dev' / infile @@ -276,7 +337,7 @@ class DependencyManager: def combine_json(root_dir): - depfluids = DependencyManager(destination=os.path.join(root_dir, 'dev', 'all_fluids.json'), + depfluids = DependencyManager(destination=os.path.join(root_dir, 'dev', 'all_fluids.json.z'), sources=(Path(root_dir) / 'dev' / 'fluids').glob('*.json'), cachefile=Path(__file__).parent / '.fluiddepcache') @@ -299,6 +360,13 @@ def combine_json(root_dir): raise ValueError('unable to decode file %s' % file) master += [fluid] + + + all_fluids_z = zlib.compress(json.dumps(master).encode('utf-8')) + ZDEST = Path(root_dir) / 'dev' / 'all_fluids.json.z' + with ZDEST.open('wb') as fp: + fp.write(all_fluids_z) + print(ZDEST.absolute()) fp = open(os.path.join(root_dir, 'dev', 'all_fluids_verbose.json'), 'w') fp.write(json.dumps(master, **json_options)) diff --git a/externals/incbin/.travis.yml b/externals/incbin/.travis.yml new file mode 100644 index 00000000..4337da6e --- /dev/null +++ b/externals/incbin/.travis.yml @@ -0,0 +1,12 @@ +language: c + +os: +- linux +- osx + +compiler: +- gcc +- clang + +script: +- make -C test test diff --git a/externals/incbin/README.md b/externals/incbin/README.md new file mode 100644 index 00000000..43082290 --- /dev/null +++ b/externals/incbin/README.md @@ -0,0 +1,205 @@ +# incbin + +Include binary and textual files in your C/C++ applications with ease + +## Example + +``` c + #include "incbin.h" + + INCBIN(Icon, "icon.png"); + + // Reference in other translation units like this + INCBIN_EXTERN(Icon); + + // NOTE: Don't forget to use `extern "C"` in case of writing C++ code + + // You may specify an optional type for the included data array as a first + // additional argument to INCBIN, the macro is overloaded by arity. The + // default type is `unsigned char`. + INCBIN(MyType, IconTyped, "icon.png"); + + // INCTXT is the same as INCBIN but it uses type `char` by default and + // implicitly adds a NUL-terminator byte to the included data, making it + // safe to use as a string in C. + INCTXT(Readme, "readme.md"); + + // Reference in other translation units like this + INCTXT_EXTERN(Readme); + + // NOTE: Since INCTXT adds a NUL-terminator byte, it's size is one byte + // larger than that of INCBIN, so subtract one for string length. + + // The macros produce three global (or external) symbols of the form + // [] + // * + // unsigned int + // + // The by default is unsigned char, unless optionally provided. + // The by default is "g", you can override it with INCBIN_PREFIX. + // The is the identifier you give to INCBIN or INCTXT. + // The , , and are tokens that depend on INCBIN_STYLE, by + // default they're "Data", "End", and "Size", but they can be changed to + // "_data", "_end", and "_size" if INCBIN_STYLE is set to INCBIN_STYLE_SNAKE. +``` + +## Portability + +Known to work on the following compilers + +* GCC +* Clang +* PathScale +* Intel +* Solaris & Sun Studio +* Green Hills +* SNC (ProDG) +* Diab C++ (WindRiver) +* XCode +* ArmCC +* RealView +* ImageCraft +* Stratus VOS C +* TinyCC +* cparser & libfirm +* LCC +* MSVC _See MSVC below_ + +If your compiler is not listed, as long as it supports GCC inline assembler, this +should work. + +## MISRA +INCBIN can be used in MISRA C setting. However it should be independently checked +due to its use of inline assembly to achieve what it does. Independent verification +of the header has been done several times based on commit: 7e327a28ba5467c4202ec37874beca7084e4b08c + +## Alignment + +The data included by this tool will be aligned on the architectures word boundary +unless some variant of SIMD is detected, then it's aligned on a byte boundary that +respects SIMD convention just incase your binary data may be used in vectorized +code. The table of the alignments for SIMD this header recognizes is as follows: + +| SIMD | Alignment | +|-----------------------------------------|-----------| +| SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 | 16 | +| Neon, AltiVec | 16 | +| AVX, AVX2 | 32 | +| AVX512 | 64 | + +## Prefix +By default, `incbin.h` emits symbols with a `g` prefix. This can be adjusted by +defining `INCBIN_PREFIX` before including `incbin.h` with a desired prefix. For +instance + +``` c + #define INCBIN_PREFIX g_ + #include "incbin.h" + INCBIN(test, "test.txt"); + + // This translation unit now has three symbols + // const unsigned char g_[]; + // const unsigned char *const g_; + // const unsigned int g_; +``` + +You can also choose to have no prefix by defining the prefix with nothing, for example: + +``` c + #define INCBIN_PREFIX + #include "incbin.h" + INCBIN(test, "test.txt"); + + // This translation unit now has three symbols + // const unsigned char []; + // const unsigned char *const ; + // const unsigned int ; +``` + +## Style +By default, `incbin.h` emits symbols with `CamelCase` style. This can be adjusted +by defining `INCBIN_STYLE` before including `incbin.h` to change the style. There +are two possible styles to choose from + +* INCBIN_STYLE_CAMEL (CamelCase) +* INCBIN_STYLE_SNAKE (snake_case) + +For instance: + +``` c + #define INCBIN_STYLE INCBIN_STYLE_SNAKE + #include "incbin.h" + INCBIN(test, "test.txt"); + + // This translation unit now has three symbols + // const unsigned char _data[]; + // const unsigned char *const _end; + // const unsigned int _size; +``` + +Combining both the style and prefix allows for you to adjust `incbin.h` to suite +your existing style and practices. + +## Overriding Linker Output section +By default, `incbin.h` emits into the read-only linker output section used on +the detected platform. If you need to override this for whatever reason, you +can manually specify the linker output section. + +For example, to emit data into program memory for +[esp8266/Arduino](github.com/esp8266/Arduino): + +``` c +#define INCBIN_OUTPUT_SECTION ".irom.text" +#include "incbin.h" +INCBIN(Foo, "foo.txt"); +// The three symbols below will all go to ".irom.text" +// [] +// * +// unsigned int +``` + +You may also override the output section for data, and size separately, this is +useful for Harvard architectures where program memory cannot be directly read +from the program without special instructions. With this you can chose to put +the size variable in RAM rather than ROM. This can be done with the macros + +```c +// and goes into custom data section +#define INCBIN_OUTPUT_DATA_SECTION "..." + +// goes into custom size section. +#define INCBIN_OUTPUT_SIZE_SECTION "..." +``` + +## Explanation + +`INCBIN` is a macro which uses the inline assembler provided by almost all +compilers to include binary files. It achieves this by utilizing the `.incbin` +directive of the inline assembler. It then uses the assembler to calculate the +size of the included binary and exports two global symbols that can be externally +referenced in other translation units which contain the data and size of the +included binary data respectively. + +## MSVC + +Supporting MSVC is slightly harder as MSVC lacks an inline assembler which can +include data. To support this we ship a tool which can process source files +containing `INCBIN` macro usage and generate an external source file containing +the data of all of them combined. This file is named `data.c` by default. +Just include it into your build and use the `incbin.h` to reference data as +needed. It's suggested you integrate this tool as part of your projects's +pre-build events so that this can be automated. A more comprehensive list of +options for this tool can be viewed by invoking the tool with `-help` + +If you're using a custom prefix, be sure to specify the prefix on the command +line with `-p ` so that everything matches up; similarly, if you're +using a custom style, be sure to specify the style on the command line with +`-S