diff --git a/.github/workflows/developer.yml b/.github/workflows/developer.yml index fa9dd0d5..6755a5f8 100644 --- a/.github/workflows/developer.yml +++ b/.github/workflows/developer.yml @@ -110,7 +110,7 @@ jobs: export CFLAGS='-Wall -g -fprofile-abs-path -fprofile-arcs -ftest-coverage -O0 -I/home/runner/g2c/include' export FCFLAGS='-Wall -g -fprofile-abs-path -fprofile-arcs -ftest-coverage -O0' export FFLAGS='-Wall -g -fprofile-abs-path -fprofile-arcs -ftest-coverage -O0' - cmake .. -DENABLE_DOCS=ON -DFTP_TEST_FILES=ON -DCMAKE_PREFIX_PATH="~/ip;~/jasper;~/g2c" -DTEST_FILE_DIR=/home/runner/data -DUSE_NETCDF4=ON -DUSE_AEC=ON -DUSE_IPOLATES=ON -DUSE_JASPER=ON + cmake .. -DENABLE_DOCS=ON -DFTP_TEST_FILES=ON -DCMAKE_PREFIX_PATH="~/ip;~/jasper;~/g2c" -DTEST_FILE_DIR=/home/runner/data -DUSE_NETCDF4=ON -DUSE_AEC=ON -DUSE_IPOLATES=ON -DUSE_JASPER=ON -DMAKE_FTN_API=ON make VERBOSE=1 ctest --verbose --output-on-failure --rerun-failed gcovr --root .. -v --html-details --exclude ../tests --exclude CMakeFiles --print-summary -o test-coverage.html &> /dev/null diff --git a/CMakeLists.txt b/CMakeLists.txt index ac62e561..5180776b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,13 @@ option(FTP_EXTRA_TEST_FILES "Fetch even more large files from FTP and test them. option(MAKE_FTN_API "add ftn api?" off) option(DISABLE_STAT "disable posix feature" off) set(BUILD_COMMENTS "stock build") + option(BUILD_LIB "Build wgrib2 library?" on) -option(BUILD_SHARED_LIB "Build shared library?" off) +# if BUILD_LIB, then code is compiled as relocatable +option(BUILD_SHARED_LIB "Build shared library?" on) +# To create libwgrib2.so for python, you have to build with BUILD_SHARED_LIB off +# and manually create libwgrib2.so from the needed *.a files + option(BUILD_WGRIB "Build wgrib code?" off) if (MAKE_FTN_API OR USE_IPOLATES) @@ -84,6 +89,10 @@ if(USE_G2CLIB) endif() endif() +if (BUILD_SHARED_LIB AND NOT BUILD_LIB) + message(FATAL_ERROR "BUILD_SHARED_LIB is on but BUILD_LIB is off") +endif() + # If user wants to use NCEPLIBS-ip, find it and the sp library. message(STATUS "Checking if the user want to use NCEPLIBS-ip...") if(USE_IPOLATES) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d14fced4..e8a0ee3b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -166,6 +166,17 @@ if (USE_JASPER OR USE_OPENJPEG) copy_test_data(ref_jpeg2simple.txt) endif() +if (MAKE_FTN_API) + shell_test(test_ftn_api) +endif() +if (BUILD_LIB) + shell_test(test_lib) +endif() +if (BUILD_SHARED_LIB) + shell_test(test_shared_lib) +endif() + + if (FTP_TEST_FILES) copy_test_data(ref_WW3_Regional_US_West_Coast_20220718_0000.grib2.inv) copy_test_data(ref_merge_fcst.aqm.t12z.max_8hr_o3.227.grib2.txt) diff --git a/tests/test_ftn_api.sh b/tests/test_ftn_api.sh new file mode 100755 index 00000000..fe8b079b --- /dev/null +++ b/tests/test_ftn_api.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# script to see if ftn_api compiled +# + +echo "see if ftn_api compiled" +set -xe + +if [ ! -f ../wgrib2/ftn_api/include/wgrib2api.mod ] ; then + echo "failed: did not find wgrib2api.mod" + exit 1 +fi + +echo "*** SUCCESS!" +exit 0 diff --git a/tests/test_lib.sh b/tests/test_lib.sh new file mode 100755 index 00000000..a7c46f1e --- /dev/null +++ b/tests/test_lib.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# script to see if shared lib was made +# + +echo "see if shared library made" +set -xe + +if [ ! -f ../wgrib2/libwgrib2.so -a ! -f ../wgrib2/libwgrib2.a ] ; then + echo "failed: did not find libwgrib2" + exit 1 +fi + +echo "*** SUCCESS!" +exit 0 diff --git a/tests/test_shared_lib.sh b/tests/test_shared_lib.sh new file mode 100755 index 00000000..fd96f986 --- /dev/null +++ b/tests/test_shared_lib.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# script to see if shared lib was made +# + +echo "see if shared library made" +set -xe + +if [ ! -f ../wgrib2/libwgrib2.so ] ; then + echo "failed: did not find libwgrib2.so" + exit 1 +fi + +echo "*** SUCCESS!" +exit 0 diff --git a/wgrib2/CMakeLists.txt b/wgrib2/CMakeLists.txt index 2bea5cd7..ec750d72 100644 --- a/wgrib2/CMakeLists.txt +++ b/wgrib2/CMakeLists.txt @@ -2,6 +2,19 @@ # subdirectory. # # Kyle Gerheiser, Edward Hartnett, Wesley Ebisuzaki +# +# if BUILD_SHARED_LIB +# ftn_api -> shared library, interface to fortran +# wgrib2_lib -> shared (includes gctpc) +# +# if !BUILD_SHARED_LIB +# ftn_api -> static library, interface to fortran +# wgrib2_lib -> static library includeing gctpc +# +# note: in wgrib2 v3.1.3 or earlier, all the libraries +# incuding aec, jasper, etc were included with the wgrib2 library +# in github version, it is different. + # sets lib_src set(lib_src AAIG.c AAIGlong.c addtime.c aec_pk.c Aerosol.c Alarm.c @@ -44,14 +57,16 @@ Type_reftime.c UDF.c Undefine.c units.c Unix_time.c Unmerge_fcst.c unpk_0.c unpk.c unpk_complex.c unpk_run_length.c update_sec3.c update_sec4.c v1_v2_if.c VerfTime.c Warn_old_g2lib.c Waves.c wgrib2_api.c wgrib2.c Wind_dir.c Wind_speed.c Wind_uv.c Write_sec.c -Wrt_grib.c wrtieee.c wxtext.c) +Wrt_grib.c wrtieee.c wxtext.c +) + +include_directories(gctpc/source/include) +add_subdirectory(gctpc) if(MAKE_FTN_API) add_subdirectory(ftn_api) endif() -add_subdirectory(gctpc) - # make this an object lib so we can re-use most of object files # The only files that differ are ${callable_src} which are compiled # with -DCALLABLE_WGRIB2 @@ -67,25 +82,27 @@ configure_file ( if(BUILD_LIB) - # with -DCALLABLE_WGRIB2 for the lib if(BUILD_SHARED_LIB) - add_library(wgrib2_lib SHARED ${lib_src} $ ${callable_src}) + add_library(wgrib2_lib SHARED ${lib_src} ) + set_property(TARGET wgrib2_lib PROPERTY POSITION_INDEPENDENT_CODE ON) else() - add_library(wgrib2_lib STATIC ${lib_src} $ ${callable_src}) + add_library(wgrib2_lib STATIC ${lib_src} $ ) +# add_library(wgrib2_lib STATIC ${lib_src} ) + set_property(TARGET wgrib2_lib PROPERTY POSITION_INDEPENDENT_CODE ON) endif() # library and executable have same name (wgrib2) but different target names set_target_properties(wgrib2_lib PROPERTIES OUTPUT_NAME wgrib2) - target_compile_definitions(wgrib2_lib PRIVATE CALLABLE_WGRIB2) + # target_compile_definitions(wgrib2_lib PRIVATE CALLABLE_WGRIB2) endif() -# without -DCALLABLE_WGRIB2 for the executable -add_executable(wgrib2_exe ${callable_src}) +add_executable(wgrib2_exe wgrib2_main.c) set_target_properties(wgrib2_exe PROPERTIES OUTPUT_NAME wgrib2) if(USE_NETCDF) target_link_libraries(obj_lib PUBLIC NetCDF::NetCDF_C) + target_link_libraries(wgrib2_exe PUBLIC NetCDF::NetCDF_C) endif() if(USE_PNG) @@ -98,6 +115,7 @@ endif() if(USE_IPOLATES) target_link_libraries(obj_lib PUBLIC ip::ip_d) + target_link_libraries(wgrib2_exe PUBLIC ip::ip_d) # Link to the Fortran runtime library for each compiler if using ip2. # The wgrib2 exectuable is created using the C compiler and @@ -110,10 +128,10 @@ if(USE_IPOLATES) endif() -target_link_libraries(obj_lib PUBLIC gctpc -lm) +## target_link_libraries(obj_lib PUBLIC gctpc -lm) -# Link to gctpc directly because oobject libraries do not link transitively -target_link_libraries(wgrib2_exe PRIVATE gctpc) +# Link to gctpc directly because object libraries do not link transitively +target_link_libraries(wgrib2_exe PRIVATE gctpc -lm) if(USE_AEC) target_link_libraries(wgrib2_exe PRIVATE ${LIBAEC_LIBRARIES}) @@ -130,10 +148,11 @@ if(USE_OPENJPEG) endif() target_link_libraries(wgrib2_exe PRIVATE obj_lib) +# target_link_libraries(wgrib2_exe PRIVATE wgrib2_lib) if(BUILD_LIB) set(headers wgrib2_api.h wgrib2.h ${CMAKE_BINARY_DIR}/wgrib2/wgrib2_meta.h) - target_link_libraries(wgrib2_lib PUBLIC gctpc) +## target_link_libraries(wgrib2_lib PUBLIC gctpc) set_target_properties(wgrib2_lib PROPERTIES PUBLIC_HEADER "${headers}") target_compile_definitions(wgrib2_lib PUBLIC ${definitions_list}) @@ -156,6 +175,3 @@ install( ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - - diff --git a/wgrib2/fatal_error.c b/wgrib2/fatal_error.c index 7b94a430..2c6d949c 100644 --- a/wgrib2/fatal_error.c +++ b/wgrib2/fatal_error.c @@ -1,9 +1,9 @@ #include #include #include -#ifdef CALLABLE_WGRIB2 + #include -#endif + #include "wgrib2.h" /* @@ -17,9 +17,9 @@ * fprintf(ARGS) * do_fatal_error_processing */ -#ifdef CALLABLE_WGRIB2 + extern jmp_buf fatal_err; -#endif + void fatal_error(const char *fmt, ...) @@ -32,9 +32,9 @@ void fatal_error(const char *fmt, ...) va_end(arg); err_bin(1); err_string(1); -#ifdef CALLABLE_WGRIB2 + longjmp(fatal_err,1); -#endif + exit(8); return; } diff --git a/wgrib2/ftn_api/CMakeLists.txt b/wgrib2/ftn_api/CMakeLists.txt index 7a8a8c3a..81a77dbc 100644 --- a/wgrib2/ftn_api/CMakeLists.txt +++ b/wgrib2/ftn_api/CMakeLists.txt @@ -13,21 +13,26 @@ set(c_src fort_wgrib2.c ) -add_library(wgrib2_api ${fortran_src} ${c_src}) +if (BUILD_SHARED_LIB) + add_library(wgrib2_ftn_api SHARED ${fortran_src} ${c_src}) +else() + add_library(wgrib2_ftn_api STATIC ${fortran_src} ${c_src}) + set_property(TARGET wgrib2_ftn_api PROPERTY POSITION_INDEPENDENT_CODE ON) +endif() set(module_dir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}") -set_target_properties(wgrib2_api PROPERTIES Fortran_MODULE_DIRECTORY ${module_dir}) +set_target_properties(wgrib2_ftn_api PROPERTIES Fortran_MODULE_DIRECTORY ${module_dir}) -target_include_directories(wgrib2_api +target_include_directories(wgrib2_ftn_api PUBLIC $ $) -target_link_libraries(wgrib2_api PUBLIC wgrib2_lib) +target_link_libraries(wgrib2_ftn_api PUBLIC wgrib2_lib) install(DIRECTORY ${module_dir} DESTINATION ${CMAKE_INSTALL_PREFIX}) install( - TARGETS wgrib2_api + TARGETS wgrib2_ftn_api EXPORT wgrib2_exports RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/wgrib2/gctpc/source/CMakeLists.txt b/wgrib2/gctpc/source/CMakeLists.txt index a077a587..8bf84a5b 100644 --- a/wgrib2/gctpc/source/CMakeLists.txt +++ b/wgrib2/gctpc/source/CMakeLists.txt @@ -1,3 +1,7 @@ +# note: this CMakelist.txt is for building the gctpc library +# wgrib2 now includes the library into the source compile +# so the wgrib2 library now include gctpc. This makes it +# easier for users who want to use the wgrib2 library. set(src alberfor.c @@ -76,7 +80,13 @@ set(src wviiinv.c ) +# if want shared library, had to make separate library +# otherwise include gctpc in libwgrib2.a + add_library(gctpc OBJECT ${src}) +if (BUILD_LIB) + set_property(TARGET gctpc PROPERTY POSITION_INDEPENDENT_CODE ON) +endif() target_include_directories(gctpc PUBLIC $ diff --git a/wgrib2/wgrib2.c b/wgrib2/wgrib2.c index 806a5f26..b948ba35 100644 --- a/wgrib2/wgrib2.c +++ b/wgrib2/wgrib2.c @@ -1,4 +1,7 @@ -/* wgrib2 main module: public domain 2005 w. ebisuzaki +/* wgrib2: public domain 2005 w. ebisuzaki + * originally the main of the wgrib2 utility + * later became main or routine depending on CALLABLE_WGRIB2 + * finally wgrib2 utility became a wrapper that calls the wgrib2 routine * * CHECK code is now duplicated * if (decode) -- check before decoding @@ -17,10 +20,9 @@ #include #include -#ifdef CALLABLE_WGRIB2 + #include jmp_buf fatal_err; -#endif #include "grb2.h" #include "wgrib2.h" @@ -116,17 +118,9 @@ int version_if; /* 0-old stype 1-modern if */ * simple wgrib for GRIB2 files * */ -#ifndef CALLABLE_WGRIB2 - -int main(int argc, const char **argv) { - -#else int wgrib2(int argc, const char **argv) { -#endif - - //WNE FILE *in; struct seq_file in_file; unsigned char *msg, *sec[10]; /* sec[9] = last valid bitmap */ @@ -176,9 +170,9 @@ int wgrib2(int argc, const char **argv) { data = NULL; // ddata = NULL; -#ifdef CALLABLE_WGRIB2 + if (setjmp(fatal_err)) { - fprintf(stderr,"*** arg list to wgrib2:"); + fprintf(stderr,"*** arg list to wgrib2(..):"); for (i=0; i < argc; i++) { fprintf(stderr," %s", argv[i]); } @@ -186,9 +180,9 @@ int wgrib2(int argc, const char **argv) { if (ndata && data != NULL) free(data); ndata=0; if (in_file.file_type != NOT_OPEN) fclose_file(&in_file); - return 1; + return 8; } -#endif + /* no arguments .. help screen */ if (argc == 1) { @@ -565,7 +559,7 @@ int wgrib2(int argc, const char **argv) { if (GDS_max_size) free(old_gds); GDS_max_size = i + 100; /* add 100 just to avoid excessive memory allocations */ if ((old_gds = (unsigned char *) malloc(GDS_max_size) ) == NULL) { - fatal_error("memory allocation problem old_gds in wgrib2.main for %s",in_file.filename); + fatal_error("memory allocation problem old_gds in wgrib2(..) for %s",in_file.filename); } } #ifdef IS_OPENMP_4_0 @@ -692,7 +686,7 @@ int wgrib2(int argc, const char **argv) { data = (float *) malloc(sizeof(float) * (size_t) ndata); if (data == NULL) { ndata = 0; - fatal_error("main: memory allocation failed data",""); + fatal_error("wgrib2(..): memory allocation failed data",""); } } else { data = NULL; } diff --git a/wgrib2/wgrib2_api.c b/wgrib2/wgrib2_api.c index d99e866d..3f081f00 100644 --- a/wgrib2/wgrib2_api.c +++ b/wgrib2/wgrib2_api.c @@ -3,7 +3,6 @@ #include #include "wgrib2.h" -#ifdef CALLABLE_WGRIB2 /* sort of like the command line version of wgrib2 @@ -43,4 +42,3 @@ int wgrib2a(char *arg1, ...) { return i; } -#endif diff --git a/wgrib2/wgrib2_main.c b/wgrib2/wgrib2_main.c new file mode 100644 index 00000000..449ce054 --- /dev/null +++ b/wgrib2/wgrib2_main.c @@ -0,0 +1,27 @@ +/* wgrib2 main module: public domain 2024 w. ebisuzaki + * + * ancient: wgrib2.c was the main for the wgrib2 utility. There was no wgrib2 library, and + * no call to the wgrib2(..). + * + * old: A user wanted to call wgrib2 from a C program. He converted wgrib2.c to be either a main(..) + * or a routine wgrib2(..) depending on a flag (CALLABLE_WGRIB2). There were two builds, + * one for the utility and a second for the library. + * + * new: move to github + * Reimplement the old idea to make the wgrib2 utility a call to wgrib2(..). + * This involves removing all references to CALLABLE_WGRIB2 + * This was tested in a pre-github version but never implemented because it provided no reward + * With github, the build system is being rebuilt from Kyle's version. Rather than the two + * builds, make it a single build with the wgrib2 utility calling wgrib2(..) + + * + * 8/2024 the main for the wgrib2 utility is moved from wgrib2.c to wgrib2_main.c + */ + +#include +#include "wgrib2_api.h" + + +int main(int argc, const char **argv) { + return wgrib2(argc, argv); +}