wgrib2 v3 系の macOS 上でのコンパイルエラーをパッチで解決する

気象業界では、数値予報や解析値などの格子点データに GRIB（現在のバージョンはバージョン2）というバイナリフォーマットが使われます。このフォーマットを扱うためのツールの1つである wgrib2 は、基本的に、公開されているソースコードを手元でビルドして使うものですが、ビルドする際に色々と落とし穴があります。執筆時点での最新版 v3.1.1 を久々に macOS でビルドしてみたら少し手こずりましたので、パッチとしてまとめてここに紹介します。

wgrib2　のビルドには昔から多くの人が苦労しており、様々なオンライン記事が見つかるため、当初はこちらに書くつもりはありませんでした。「2022 年にもなってビルド方法について書くなんて」という気持ちもあります。しかし環境によっても異なり、また　v2、v3　とバージョンを重ねるごとに（また世の中のコンパイラが進化するごとに）さらに苦労が増えている感がありますので、今一度最新状況をこちらに記載した次第です。ごちゃごちゃとした手順を書くのはあまり好きでないので、基本的にはパッチの解説というかたちをとります。

なお、基本的には私の環境で動くよう修正したものですが、「macOS Catalina での wgrib v3.1.1 のビルドにしか使えない」というわけではないはずです。少しバージョンが変わってもきちんと動くように対応したつもりですし、修正方法や考え方はほかの環境でも通じるはずです。

## 結論

まず、tarballを (`tar xf wgrib2.tgz`などで) 展開したら、下記のパッチを（`patch -p0 < grib2.diff` などで）当てましょう。

```diff
diff -ur grib2.orig/makefile grib2/makefile
--- grib2.orig/makefile	2022-04-13 23:50:45.000000000 +0900
+++ grib2/makefile	2022-07-10 02:02:34.000000000 +0900
@@ -148,7 +148,7 @@
 USE_IPOLATES=3
 USE_SPECTRAL=1
 USE_UDF=0
-USE_OPENMP=1
+USE_OPENMP=0
 USE_PROJ4=0
 USE_WMO_VALIDATION=0
 USE_NAMES=NCEP
@@ -338,9 +338,7 @@
       endif
    endif
    ifeq (${system},Darwin)
-      ifeq ($(findstring gcc,$(notdir $(CC))),gcc)
-         COMP_SYS=gnu_mac
-      endif
+      COMP_SYS=gnu_mac
    endif
 endif
 CCjasper:=${CC}
@@ -433,7 +431,7 @@
    netcdf4CPPFLAGS+=-Wall -Wmissing-prototypes -Wold-style-definition -Werror=format-security -O3
    hdf5CFLAGS+=-Wall -Wmissing-prototypes -Wold-style-definition -O1
    ifeq ($(need_ftn),1)
-      wLDFLAGS+=-lgfortran
+      wLDFLAGS+=-L$(shell gfortran -print-search-dirs | grep libraries | sed 's/^.*=//;s/:/ -L/g') -lgfortran
       wCPPFLAGS+=-DGFORTRAN
       wFFLAGS+=-c -O3
       FTN_REAL8:="-fdefault-real-8 -fdefault-double-8"
```

その上で、grib2ディレクトリ内に入り、jasper-1.900.1-14ubuntu3.2.debian.tgzを (`tar xf jasper-1.900.1-14ubuntu3.2.debian.tgz`などで) 展開します。展開したら、下記のパッチを（`patch -p0 < jasper.diff` などで）当てます。

```diff
diff -ur jasper-1.900.1.orig/src/libjasper/base/jas_getopt.c jasper-1.900.1/src/libjasper/base/jas_getopt.c
--- jasper-1.900.1.orig/src/libjasper/base/jas_getopt.c	2007-01-20 06:43:05.000000000 +0900
+++ jasper-1.900.1/src/libjasper/base/jas_getopt.c	2022-07-09 23:49:59.000000000 +0900
@@ -76,6 +76,7 @@
 
 #include "jasper/jas_getopt.h"
 #include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
 
 /******************************************************************************\
 * Global data.
diff -ur jasper-1.900.1.orig/src/libjasper/bmp/bmp_dec.c jasper-1.900.1/src/libjasper/bmp/bmp_dec.c
--- jasper-1.900.1.orig/src/libjasper/bmp/bmp_dec.c	2015-08-13 01:26:12.000000000 +0900
+++ jasper-1.900.1/src/libjasper/bmp/bmp_dec.c	2022-07-09 23:51:53.000000000 +0900
@@ -77,6 +77,7 @@
 #include "jasper/jas_stream.h"
 #include "jasper/jas_image.h"
 #include "jasper/jas_malloc.h"
+#include "jasper/jas_debug.h"
 
 #include "bmp_cod.h"
 
diff -ur jasper-1.900.1.orig/src/libjasper/jpc/jpc_t1dec.c jasper-1.900.1/src/libjasper/jpc/jpc_t1dec.c
--- jasper-1.900.1.orig/src/libjasper/jpc/jpc_t1dec.c	2007-01-20 06:43:07.000000000 +0900
+++ jasper-1.900.1/src/libjasper/jpc/jpc_t1dec.c	2022-07-09 23:53:44.000000000 +0900
@@ -78,6 +78,7 @@
 #include "jasper/jas_fix.h"
 #include "jasper/jas_stream.h"
 #include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
 
 #include "jpc_bs.h"
 #include "jpc_mqdec.h"
diff -ur jasper-1.900.1.orig/src/libjasper/jpc/jpc_tsfb.c jasper-1.900.1/src/libjasper/jpc/jpc_tsfb.c
--- jasper-1.900.1.orig/src/libjasper/jpc/jpc_tsfb.c	2007-01-20 06:43:07.000000000 +0900
+++ jasper-1.900.1/src/libjasper/jpc/jpc_tsfb.c	2022-07-10 00:01:04.000000000 +0900
@@ -119,6 +119,9 @@
 	free(tsfb);
 }
 
+int jpc_tsfb_analyze2(jpc_tsfb_t *tsfb, int *a, int xstart, int ystart,
+  int width, int height, int stride, int numlvls);
+
 int jpc_tsfb_analyze(jpc_tsfb_t *tsfb, jas_seq2d_t *a)
 {
 	return (tsfb->numlvls > 0) ? jpc_tsfb_analyze2(tsfb, jas_seq2d_getref(a,
@@ -146,6 +149,9 @@
 	return 0;
 }
 
+int jpc_tsfb_synthesize2(jpc_tsfb_t *tsfb, int *a, int xstart, int ystart,
+  int width, int height, int stride, int numlvls);
+
 int jpc_tsfb_synthesize(jpc_tsfb_t *tsfb, jas_seq2d_t *a)
 {
 	return (tsfb->numlvls > 0) ? jpc_tsfb_synthesize2(tsfb,
diff -ur jasper-1.900.1.orig/src/libjasper/jpg/jpg_dummy.c jasper-1.900.1/src/libjasper/jpg/jpg_dummy.c
--- jasper-1.900.1.orig/src/libjasper/jpg/jpg_dummy.c	2007-01-20 06:43:04.000000000 +0900
+++ jasper-1.900.1/src/libjasper/jpg/jpg_dummy.c	2022-07-10 00:05:23.000000000 +0900
@@ -69,6 +69,7 @@
 #include "jasper/jas_stream.h"
 #include "jasper/jas_image.h"
 #include "jasper/jas_string.h"
+#include "jasper/jas_debug.h"
 
 #include "jpg_cod.h"
 
diff -ur jasper-1.900.1.orig/src/libjasper/mif/mif_cod.c jasper-1.900.1/src/libjasper/mif/mif_cod.c
--- jasper-1.900.1.orig/src/libjasper/mif/mif_cod.c	2015-08-13 01:26:12.000000000 +0900
+++ jasper-1.900.1/src/libjasper/mif/mif_cod.c	2022-07-10 00:01:56.000000000 +0900
@@ -70,6 +70,7 @@
 #include "jasper/jas_image.h"
 #include "jasper/jas_string.h"
 #include "jasper/jas_malloc.h"
+#include "jasper/jas_debug.h"
 
 #include "mif_cod.h"
 
diff -ur jasper-1.900.1.orig/src/libjasper/pnm/pnm_dec.c jasper-1.900.1/src/libjasper/pnm/pnm_dec.c
--- jasper-1.900.1.orig/src/libjasper/pnm/pnm_dec.c	2007-01-20 06:43:05.000000000 +0900
+++ jasper-1.900.1/src/libjasper/pnm/pnm_dec.c	2022-07-10 00:03:35.000000000 +0900
@@ -79,6 +79,7 @@
 #include "jasper/jas_types.h"
 #include "jasper/jas_stream.h"
 #include "jasper/jas_image.h"
+#include "jasper/jas_debug.h"
 
 #include "pnm_cod.h"
 
```

あとは以下のようにビルドをすれば、`wgrib` ディレクトリ以下に `wgrib2` という実行ファイルができます。パスの通っている適当なディレクトリに持っていってあげれば、インストール完了です。

```shell
FC=gfortran CC=cc gmake
```

## 解説

hunk ごとに説明していきます。

### USE_OPENMP=0

```diff
@@ -148,7 +148,7 @@
 USE_IPOLATES=3
 USE_SPECTRAL=1
 USE_UDF=0
-USE_OPENMP=1
+USE_OPENMP=0
 USE_PROJ4=0
 USE_WMO_VALIDATION=0
 USE_NAMES=NCEP
```

これは、私の環境には OpenMP を入れていないためです。もっとも、Apple Clang でも OpenMP は使えるはずですので、きちんと環境を整えれば問題ないはずです。動作確認ができましたら記載をアップデートします。

### COMP_SYS=gnu_mac

```diff
@@ -338,9 +338,7 @@
       endif
    endif
    ifeq (${system},Darwin)
-      ifeq ($(findstring gcc,$(notdir $(CC))),gcc)
-         COMP_SYS=gnu_mac
-      endif
+      COMP_SYS=gnu_mac
    endif
 endif
 CCjasper:=${CC}
```

wgrib2 の `makefile` では各プラットフォームのための条件分岐に `COMP_SYS` という変数を用いており、コンパイラを意味する変数 `CC` を `gcc` にしていないと `COMP_SYS` が設定されず空のままになります。ここでは、`CC` が `gcc` 以外でも `COMP_SYS` が　`gnu_mac`　に設定されるようにしています。

`makefile` の後の方で、`ifeq (${COMP_SYS},gnu_mac)` のような条件分岐で各プラットフォーム用のコンパイラやリンカのための様々な変数を設定しているので、最初に `COMP_SYS` が設定されないと変なビルドエラーが色々と発生してハマります。私は　`CC` を `cc` にしていたので結構ハマりました。

そもそも macOS の標準的な環境では、`gcc` コマンドは `clang` のランチャーに過ぎません。そのため、この `makefile` の「`CC` として `gcc` 以外は認めない」というやりかたは少しやりすぎな感じがしますので、ここでは条件を緩和するという方法をとりました。

### wLDFLAGS+=...

```diff
@@ -433,7 +431,7 @@
    netcdf4CPPFLAGS+=-Wall -Wmissing-prototypes -Wold-style-definition -Werror=format-security -O3
    hdf5CFLAGS+=-Wall -Wmissing-prototypes -Wold-style-definition -O1
    ifeq ($(need_ftn),1)
-      wLDFLAGS+=-lgfortran
+      wLDFLAGS+=-L$(shell gfortran -print-search-dirs | grep libraries | sed 's/^.*=//;s/:/ -L/g') -lgfortran
       wCPPFLAGS+=-DGFORTRAN
       wFFLAGS+=-c -O3
       FTN_REAL8:="-fdefault-real-8 -fdefault-double-8"
```

これをつけないとリンカが正しく libgfortran を見つけられず、下記のように最後に libgfortran とリンクする際にエラーが出ます。

```
cc -o wgrib2  -I/Users/noritada/work/lab/wgrib2/20220707/grib2/include -Wall -Wmissing-prototypes -Wold-style-definition -Werror=format-security -ffast-math -O3 -DGFORTRAN -I/Users/noritada/work/lab/wgrib2/20220707/grib2/jasper-1.900.1/src/libjasper/include  AAIG.o AAIGlong.o Aerosol.o Alarm.o Alias.o Ave_test.o Ave_var.o Bbox.o Box_ave.o Check_pdt_size.o Checksum.o Cluster.o CodeTable.o Code_Values.o Config.o Cress_lola.o Csv.o Csv_long.o CubeFace2global.o Cyclic.o Data.o Dump.o EOF.o Earth.o Else.o End.o Endif.o Ens_processing.o Ens_qc.o Ensemble.o Export_lonlat.o ExtName.o Fcst_ave.o Fi.o File.o Fix_CFSv2_fcst.o Fix_ncep.o Fix_ncep_2.o Fix_ncep_3.o Fix_ncep_4.o Fix_undef.o FlagTable.o Flush.o For.o Ftime.o Ftime1.o Ftime2.o Ftn_api.o GDT.o Gctpc.o Geolocation.o Grads.o Grib.o Grib_out_irr.o Grib_out_irr2.o Gribtable_used.o Grid_def.o Grid_id.o Gridout.o Help.o Hybrid.o If_delayed_error.o If_rec.o Import.o Import_grib.o Import_grib_fs.o Import_lonlat.o Import_netcdf.o Inv.o Inv_no.o Irr_grids.o JMA.o Last.o Latlon.o Level.o Limit.o Lola.o Macro.o Match.o Match_fs.o Match_inv.o Mem_buffer.o Merge.o Misc.o Mod_grib.o Model_version_date.o Mysql.o Mysql_dump.o Mysql_speed.o NCEP_norm.o NCEP_uv.o Names.o Ncpu.o Ndate.o Ndates.o Netcdf.o Netcdf_sup.o New_grid.o New_grid_order.o Precision.o Prob.o Proj4.o PyInv.o RPN.o Range.o Reduced_gaussian_grid.o Reset_delayed_error.o Scaling_0001.o Scan.o Sec0.o Sec1.o Sec3.o Sec4.o Sec5.o Sec6.o Sec_len.o Set_byte.o Set_date.o Set_ens_num.o Set_ensm_derived_fcst.o Set_ftime1.o Set_ftime2.o Set_gds.o Set_metadata.o Set_pdt.o Set_percentile.o Set_prob.o Set_sec_size.o Set_ts_dates.o Set_val.o Small_grib.o SpatialProcessing.o Spectral_bands.o Status.o Submsg_uv.o Summary.o Tigge.o Time_processing.o Timer.o Tosubmsg.o UDF.o Undefine.o Unix_time.o Unix_time_old.o Unmerge_fcst.o VerfTime.o Warn_old_g2lib.o Waves.o Wind_dir.o Wind_speed.o Wind_uv.o Write_sec.o Wrt_grib.o addtime.o aec_pk.o bitstream.o cname.o codetable_4_230.o complex_pk.o copy.o crc32.o cubed_sphere2ll.o dec_png_clone.o decenc_openjpeg.o enc_jpeg2000_clone.o fatal_error.o ffopen.o flt2ieee.o flt2ieee_nan.o fnlist.o gaussian2ij.o gctpc_ll2xy.o geo.o get_unixtime.o gribtab.o grid_ident.o ieee2flt.o ieee2flt_nan.o ieee_pk.o init.o int8.o intpower.o itoshort_a.o jpeg_pk.o lat2ij.o manage_inv_out.o missing.o mk_gdt.o mk_kgds.o ncep_grids.o new_grid_lambertc.o openmp_util.o parse_loop.o parse_msg.o pdt_len.o proj4_initialize.o proj4_transform.o rd_inventory.o rd_seq_grib.o rdieee_file.o read_latlon.o rotll.o save_string.o sec3_grids.o setup_user_gribtable.o simple_pk.o space_view.o space_view2ij.o stagger.o string2time_unit.o subtime.o swap_buffer.o test_sec.o units.o unpk.o unpk_0.o unpk_complex.o unpk_run_length.o update_sec3.o update_sec4.o v1_v2_if.o wgrib2.o wgrib2_api.o wrtieee.o wxtext.o -L/Users/noritada/work/lab/wgrib2/20220707/grib2/lib -lip2_d -lgfortran -lgeo -ljasper -laec -lsp_v2.0.2_d -lnetcdf -lpng12 -lz -lm
ld: library not found for -lgfortran
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [wgrib2] Error 1
```

これは、libgfortran が入っているディレクトリにライブラリの検索パスが通っていないためです。私の環境だと、libfortran の実体は以下にありました。

```console
%  ls /usr/local/Cellar/gcc/11.3.0_2/lib/gcc/11/libgfortran.*
/usr/local/Cellar/gcc/11.3.0_2/lib/gcc/11/libgfortran.5.dylib
/usr/local/Cellar/gcc/11.3.0_2/lib/gcc/11/libgfortran.a
/usr/local/Cellar/gcc/11.3.0_2/lib/gcc/11/libgfortran.dylib
/usr/local/Cellar/gcc/11.3.0_2/lib/gcc/11/libgfortran.spec
```

また、以下のように、symlink を通じたアクセスも可能です。

```console
% ls -l /usr/local/lib/gcc                                                                          1395-koba-n-pro-14-1:/usr/local/Cellar/gcc/11.3.0_2/lib/gcc/11
lrwxr-xr-x  1 noritada  admin  30  7  9 02:02 /usr/local/lib/gcc -> ../Cellar/gcc/11.3.0_2/lib/gcc

% ls /usr/local/lib/gcc/11/libgfortran.*
/usr/local/lib/gcc/11/libgfortran.5.dylib
/usr/local/lib/gcc/11/libgfortran.a
/usr/local/lib/gcc/11/libgfortran.dylib
/usr/local/lib/gcc/11/libgfortran.spec
```

しかし、libgfortran の実体は、私の後輩の環境では `/opt/homebrew/Cellar/gcc/11.3.0_2` に入っているなど環境依存なので、バージョンも含めハードコードしてしまう解決策は不適切です。

実は、`libgfortran` の実体などを含むディレクトリへのパスのリストは、`gfortran` コマンドを用いて `gfortran -print-search-dirs` で出力できます。出力はちょっと長いですし、親ディレクトリ参照もパスの中に大量に含まれていてわかりにくいのですが、出力内の`libraries` の一番最後に含まれている `/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../` が、実際に libgfortran の実体が含まれている `/usr/local/Cellar/gcc/11.3.0_2/lib/gcc/11` になります。

```console
% gfortran -print-search-dirs
install: /usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/
programs: =/usr/local/Cellar/gcc/11.3.0_2/bin/../libexec/gcc/x86_64-apple-darwin19/11/:/usr/local/Cellar/gcc/11.3.0_2/bin/../libexec/gcc/:/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../../../../x86_64-apple-darwin19/bin/x86_64-apple-darwin19/11/:/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../../../../x86_64-apple-darwin19/bin/
libraries: =/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/:/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/:/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../../../../x86_64-apple-darwin19/lib/x86_64-apple-darwin19/11/:/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../../../../x86_64-apple-darwin19/lib/:/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../x86_64-apple-darwin19/11/:/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../
```

今回の `makefile` の変更では、下記のようにこの `gfortran -print-search-dirs` の出力をワンライナーでパスのリストへと変換し、`wLDFLAGS` に追加しています。

```
% gfortran -print-search-dirs | grep libraries | sed 's/^.*=//;s/:/ -L/g'                            1395-koba-n-pro-14-1:/usr/local/Cellar/gcc/11.3.0_2/lib/gcc/11
/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/ -L/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/ -L/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../../../../x86_64-apple-darwin19/lib/x86_64-apple-darwin19/11/ -L/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../../../../x86_64-apple-darwin19/lib/ -L/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../x86_64-apple-darwin19/11/ -L/usr/local/Cellar/gcc/11.3.0_2/bin/../lib/gcc/11/gcc/x86_64-apple-darwin19/11/../../../
```

### Jasper関連

Jasper に関してはかなりあちこちでコンパイルエラーが発生します。本家の Jasper の最新版は執筆時点で v3.0.5 ですが、wgrib2 の　tarball に同包されているのは v1.900.1 と、かなり古いバージョンなのが根本的な問題です。

本家では保守がきちんとなされているので、新しいビルドツールへの対応や最近の C 標準への対応、最近のコンパイラの厳格なチェックに起因する警告やエラーへの対応なども継続的になされ、新しいバージョンとしてリリースされているはずです。しかし、この tarball に含まれているのは古いバージョンなので、最近のコンパイラやビルドツールに強引に対応させるしかありません。

#### #include "jasper/jas_debug.h"

```diff
@@ -76,6 +76,7 @@
 
 #include "jasper/jas_getopt.h"
 #include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
 
 /******************************************************************************\
 * Global data.
```

下記のように、`jas_eprintf()` という関数の宣言が見つからないと言われますので、見つかるようにしてあげています。このエラーは複数ファイルについて発生するので、それぞれ同じ対応を入れています。

```
if /bin/sh ../../../libtool --tag=CC --mode=compile cc -DHAVE_CONFIG_H -I. -I. -I../../../src/libjasper/include/jasper -I../../../src/libjasper/include     -MT jas_getopt.lo -MD -MP -MF ".deps/jas_getopt.Tpo" -c -o jas_getopt.lo jas_getopt.c; \
	then mv -f ".deps/jas_getopt.Tpo" ".deps/jas_getopt.Plo"; else rm -f ".deps/jas_getopt.Tpo"; exit 1; fi
 cc -DHAVE_CONFIG_H -I. -I. -I../../../src/libjasper/include/jasper -I../../../src/libjasper/include -MT jas_getopt.lo -MD -MP -MF .deps/jas_getopt.Tpo -c jas_getopt.c -o jas_getopt.o
jas_getopt.c:129:7: error: implicit declaration of function 'jas_eprintf' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
                                                jas_eprintf("unknown long option %s\n", s);
                                                ^
jas_getopt.c:140:7: error: implicit declaration of function 'jas_eprintf' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
                                                jas_eprintf("unknown short option %s\n", s);
                                                ^
jas_getopt.c:151:7: error: implicit declaration of function 'jas_eprintf' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
                                                jas_eprintf("missing argument for option %s\n", s);
                                                ^
3 errors generated.
make[4]: *** [jas_getopt.lo] Error 1
```

#### 関数宣言の追加

```diff
@@ -119,6 +119,9 @@
 	free(tsfb);
 }
 
+int jpc_tsfb_analyze2(jpc_tsfb_t *tsfb, int *a, int xstart, int ystart,
+  int width, int height, int stride, int numlvls);
+
 int jpc_tsfb_analyze(jpc_tsfb_t *tsfb, jas_seq2d_t *a)
 {
 	return (tsfb->numlvls > 0) ? jpc_tsfb_analyze2(tsfb, jas_seq2d_getref(a,
@@ -146,6 +149,9 @@
 	return 0;
 }
 
+int jpc_tsfb_synthesize2(jpc_tsfb_t *tsfb, int *a, int xstart, int ystart,
+  int width, int height, int stride, int numlvls);
+
 int jpc_tsfb_synthesize(jpc_tsfb_t *tsfb, jas_seq2d_t *a)
 {
 	return (tsfb->numlvls > 0) ? jpc_tsfb_synthesize2(tsfb,
```

下記のように、ファイル内の後ろのほうで定義されている関数の宣言が見つからないと言われますので、見つかるようにしてあげています。

```
 cc -DHAVE_CONFIG_H -I. -I. -I../../../src/libjasper/include/jasper -I../../../src/libjasper/include -MT jpc_tsfb.lo -MD -MP -MF .deps/jpc_tsfb.Tpo -c jpc_tsfb.c -o jpc_tsfb.o
jpc_tsfb.c:124:31: error: implicit declaration of function 'jpc_tsfb_analyze2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        return (tsfb->numlvls > 0) ? jpc_tsfb_analyze2(tsfb, jas_seq2d_getref(a,
                                     ^
jpc_tsfb.c:124:31: note: did you mean 'jpc_tsfb_analyze'?
jpc_tsfb.c:122:5: note: 'jpc_tsfb_analyze' declared here
int jpc_tsfb_analyze(jpc_tsfb_t *tsfb, jas_seq2d_t *a)
    ^
jpc_tsfb.c:151:31: error: implicit declaration of function 'jpc_tsfb_synthesize2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        return (tsfb->numlvls > 0) ? jpc_tsfb_synthesize2(tsfb,
                                     ^
jpc_tsfb.c:151:31: note: did you mean 'jpc_tsfb_synthesize'?
jpc_tsfb.c:149:5: note: 'jpc_tsfb_synthesize' declared here
int jpc_tsfb_synthesize(jpc_tsfb_t *tsfb, jas_seq2d_t *a)
    ^
2 errors generated.
make[4]: *** [jpc_tsfb.lo] Error 1
```

## 環境

上記は以下の環境で動作確認しました。

```console
% uname -a
Darwin macbook-pro.local 19.6.0 Darwin Kernel Version 19.6.0: Mon Apr 18 21:50:40 PDT 2022; root:xnu-6153.141.62~1/RELEASE_X86_64 x86_64

% ls -l `which cc`
lrwxr-xr-x  1 root  wheel  5 11 22  2020 /usr/bin/cc -> clang

% ls -l `which gfortran`
lrwxr-xr-x  1 noritada  staff  35  7  9 02:02 /usr/local/bin/gfortran -> ../Cellar/gcc/11.3.0_2/bin/gfortran

% cc --version
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

% gfortran --version
GNU Fortran (Homebrew GCC 11.3.0_2) 11.3.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

## おまけ：makefile (GNU make) のデバッグ方法

ビルド時にエラーが発生したときは、`gmake` コマンドの出力を眺め、内部で実行されるコマンドに変数が正しく設定されていそうか確認しましょう。

怪しい場合は、変数を出力する命令を　`makefile` 内に書く、いわゆるデバッグプリントをするのが簡単です。今回はGNU makeなので `$(warning text...)` という命令です。例えばこんな感じになります。

```gnumake
$(warning COMP_SYS = $(COMP_SYS))
```

もちろん、`makefile` を読むのも大切です。詳しくは下記を参照するとよいでしょう。

- [Makefile の関数](https://qiita.com/chibi929/items/b8c5f36434d5d3fbfa4a)
- [GNU make のドキュメント](https://www.gnu.org/software/make/manual/html_node/index.html#Top)の [Functions for Transforming Text](https://www.gnu.org/software/make/manual/html_node/Functions.html#Functions)

## おまけ：2022 年の GRIB バージョン2 (GRIB2) 処理ツール

一昔前は wgrib2 一択という感じだった気がしますが（間違っていたらすみません）、GRIB2 フォーマットのデータを扱える処理系は、世の中に増えてきています。代表的なものを下記に挙げます。もし、何か重要なものを紹介し忘れていたらご指摘ください。

- [wgrib2](https://www.cpc.ncep.noaa.gov/products/wesley/wgrib2/)：アメリカの NCEP（国立環境予測センター）が古くから公開しているコマンドラインツール。C で書かれている。最近は共有ライブラリ経由で Python からアクセスできるインタフェースも作られている。
- [ecCodes](https://confluence.ecmwf.int/display/ECC)：ECMWF（ヨーロッパ中期予報センター）が公開しているソフトウェアライブラリ。開発自体も[GitHub上](https://github.com/ecmwf/eccodes)で行われている。C で書かれているが、Python用インタフェースも存在し、[eccodes](https://pypi.org/project/eccodes/) としてPyPiで公開されている。
- [pygrib](https://jswhit.github.io/pygrib/)：Jeff Whitaker 氏が [GitHub上](https://github.com/jswhit/pygrib)で個人で開発、[PyPi で公開](https://pypi.org/project/pygrib/)している Python モジュール。ecCodes の高レベルインタフェースとして作られており、インタフェースは Python だが、実質的には Cython で書かれている。
- [grib-rs](https://github.com/noritada/grib-rs)：代表的というにはまだまだだが、私がひっそりとスクラッチから Rust で書いている。まだまだ基本機能を充実させている段階。

なお、気象データ全体という観点では、ほかにも NetCDF など様々なデータフォーマットが使われています。色々なフォーマットを扱えるよう、上記処理系の上に作られているソフトウェアもあります。