GNU Makeのインストール

stowによるローカルパッケージ管理」でパッケージのソースコードからのインストール方法について解説した。基本的に,新規でインストールするパッケージはこの方法でソースコードからインストールする。

ソースコードからインスト―ルするにあたって,多数のソフトがビルドに採用しているGNU Makeをソースコードからインストールする。

インストール手順

インストール情報
項目 説明
配布元
リポジトリー
手順
依存情報
依存先 (必須)
  • Cコンパイラー(GCC)
依存先 (任意)
  • Autoconf: リポジトリーからのビルドに必要。
  • Automake: リポジトリーからのビルドに必要。
  • Make (GNU Make): リポジトリーからのビルドに必要。
  • GNU Texinfo: リポジトリーからのビルドに必要。
  • wget: リポジトリーからのビルドに必要。
  • gnulib: make gendocsでマニュアルの生成に必要。
  • GNU Guile: GNU Make内でのGuile言語の埋め込み対応。
依存元
インストール手順
sh -eux <<-"EOT"
LOCAL=~/.local J=$(grep -cs '^processor' /proc/cpuinfo || echo 2)
PKG=make VER=4.2.1 TAG=$VER
mkdir -p "$LOCAL/src"; cd "$LOCAL/src"

if (command -v git && command -v make) >/dev/null; then
  [ -e $PKG ] || git clone --depth 1 git://git.savannah.gnu.org/$PKG.git $PKG
  cd $PKG
  git fetch --depth 1 origin tag $TAG
  git checkout $TAG
  autoreconf -i
else
  [ -e $PKG-$VER ] || wget https://ftp.gnu.org/gnu/$PKG/$PKG-$VER.tar.gz
  tar -xf $PKG-$VER.*
  cd $PKG-$VER
fi

[ $(echo $VER | sed 's/[^0-9]//g') -le 421 ] && patch -N <<-EOP || :
diff --git a/configure.ac b/configure.ac
index 8c72568..4710832 100644
--- a/configure.ac
+++ b/configure.ac
@@ -404,10 +404,9 @@ AC_CACHE_CHECK([if system libc has GNU glob], [make_cv_sys_gnu_glob],
 #include <glob.h>
 #include <fnmatch.h>
 
-#define GLOB_INTERFACE_VERSION 1
 #if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
 # include <gnu-versions.h>
-# if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION
+# if _GNU_GLOB_INTERFACE_VERSION == 1 || _GNU_GLOB_INTERFACE_VERSION == 2
    gnu glob
 # endif
 #endif],

diff --git a/dir.c b/dir.c
index adbb8a9..c343e4c 100644
--- a/dir.c
+++ b/dir.c
@@ -1299,15 +1299,40 @@ local_stat (const char *path, struct stat *buf)
 }
 #endif
 
+/* Similarly for lstat.  */
+#if !defined(lstat) && !defined(WINDOWS32) || defined(VMS)
+# ifndef VMS
+#  ifndef HAVE_SYS_STAT_H
+int lstat (const char *path, struct stat *sbuf);
+#  endif
+# else
+    /* We are done with the fake lstat.  Go back to the real lstat */
+#   ifdef lstat
+#     undef lstat
+#   endif
+# endif
+# define local_lstat lstat
+#elif defined(WINDOWS32)
+/* Windows doesn't support lstat().  */
+# define local_lstat local_stat
+#else
+static int
+local_lstat (const char *path, struct stat *buf)
+{
+  int e;
+  EINTRLOOP (e, lstat (path, buf));
+  return e;
+}
+#endif
+
 void
 dir_setup_glob (glob_t *gl)
 {
   gl->gl_opendir = open_dirstream;
   gl->gl_readdir = read_dirstream;
   gl->gl_closedir = free;
+  gl->gl_lstat = local_lstat;
   gl->gl_stat = local_stat;
-  /* We don't bother setting gl_lstat, since glob never calls it.
-     The slot is only there for compatibility with 4.4 BSD.  */
 }
 
 void
EOP

command -v make >/dev/null && make -kj $J distclean clean || :
./configure --prefix="$LOCAL/stow/$PKG-$VER"

if command -v make >/dev/null; then
  make -j $J update
  make -j $J
else
  ./build.sh
fi

./make -j $J PERL_USE_UNSAFE_INC=1 check
./make -j $J install
cd "$LOCAL/stow"
command -v stow >/dev/null && stow --ignore=dir -S $PKG-$VER -D $PKG-[0-9]*
EOT
インストール例
日付 バージョン OS 依存関係
2018-04-07 4.2.1 Ubuntu 16.04
2019-03-13 4.2.1 Ubuntu 18.04 GNU Make 4.2.1, GCC 7.4.0, GNU Texinfo 6.6

GNU Makeのインストールでは,makeコマンドが存在するかどうかでビルド方法が変わる。リポジトリーからのビルドには,makeが必須となる。従って,GNU Makeが存在しない場合,配布用ソースコード (tar.gz) からビルドすることになる。

makeなしでのGNU Makeのインストール

GNU MakeもビルドにAutotoolsやMakeを採用しているため,本来ならばGNU Makeのビルド自体にもGNU Makeが必要だ。しかし,GNU Makeはインストールできていない場合,GNU Makeをインストールできない。この「自分自身を生成するのに自分自身が必要となる問題」をブートストラップ問題と呼ぶ。

GNU Makeでは,ブートストラップ問題の対策として,GNU Makeが存在しない環境でGNU Makeをビルドするためのシェルスクリプトbuild.shが用意されている。

If you need to build GNU Make and
have no other ‘make’ program to use, you can use the shell script
‘build.sh’ instead. To do this, first run ‘configure’ as described in
INSTALL. Then, instead of typing ‘make’ to build the program, type ‘sh
build.sh’. This should compile the program in the current directory.
Then you will have a Make program that you can use for ‘./make install’,
or whatever else.
Some systems’ Make programs cannot process the
Makefile for GNU Make. If you get errors from your system’s Make when
building GNU Make, try using ‘build.sh’ instead.

README.template – make.git – make

GNU Makeの配布用ソースコード (tar.gz) にはbuild.shのテンプレートであるbuild.sh.inが同梱されており,configure実行時にbuild.sh.inからbuild.shが生成される。このbuild.shを使うことで,makeなしでGNU Makeをインストールできる。インストール手順では,93行目で./build.shでGNU Makeをビルドしている。

ただし,このbuild.shは配布用ソースコード (tar.gz) にしか含まれておらず,リポジトリーからのビルドにはmakeが必須であることに注意する。

リポジトリーからのビルド

GNU MakeをGitリポジトリーからビルドする場合,注意が必要だ。リリース用のtar.gzには,build.sh.inが同梱されているが,リポジトリー上には含まれていないためだ。build.sh.inを自分で生成する必要があり,build.sh.inの生成にmakeが必要だ。

そのため,6行目のgitリポジトリーを使う際の判定 (command -v) に,makeコマンドも追加した。リポジトリーからのビルド手順は「README.git – make.git – make」に記載がある。

ここにある通り,makeの実行前にmake updateが必要だ。インストール手順では,89行目からmakeが存在する場合にmake updateを実行するようにしている。

./make updateを実行しない場合,翻訳関係のファイルが不足するため,./make install時に以下のエラーが出る。

Making install in po
make[1]: Entering directory '/home/senooken/.local/src/make/po'
test ! -f ./make.pot || \
  test -z "be.gmo cs.gmo da.gmo de.gmo es.gmo fi.gmo fr.gmo ga.gmo gl.gmo he.gmo hr.gmo id.gmo it.gmo ja.gmo ko.gmo lt.gmo nl.gmo pl.gmo pt_BR.gmo ru.gmo sv.gmo tr.gmo uk.gmo vi.gmo zh_CN.gmo" || /home/senooken/.local/src/make/./make be.gmo cs.gmo da.gmo de.gmo es.gmo fi.gmo fr.gmo ga.gmo gl.gmo he.gmo hr.gmo id.gmo it.gmo ja.gmo ko.gmo lt.gmo nl.gmo pl.gmo pt_BR.gmo ru.gmo sv.gmo tr.gmo uk.gmo vi.gmo zh_CN.gmo
make[2]: Entering directory '/home/senooken/.local/src/make/po'
make[3]: Entering directory '/home/senooken/.local/src/make/po'
File be.po does not exist. If you are a translator, you can create it through 'msginit'.
make[3]: *** [Makefile:511: be.po-create] Error 1

また,./make update実行後に./make installする場合,GNU Texinfoに含まれるmakeinfoコマンドが必要となる。GNU Texinfoをインストールしていない場合,./make install実行時に以下のエラーが出てしまう。

make[1]: Entering directory '/home/senooken/.local/src/make/doc'
restore=: && backupdir=".am$$" && \
am__cwd=`pwd` && CDPATH="${ZSH_VERSION+.}:" && cd . && \
rm -rf $backupdir && mkdir $backupdir && \
if (/bin/bash /home/senooken/.local/src/make/config/missing makeinfo --version) >/dev/null 2>&1; then \
  for f in make.info make.info-[0-9] make.info-[0-9][0-9] make.i[0-9] make.i[0-9][0-9]; do \
    if test -f $f; then mv $f $backupdir; restore=mv; else :; fi; \
  done; \
else :; fi && \
cd "$am__cwd"; \
if /bin/bash /home/senooken/.local/src/make/config/missing makeinfo   -I . \
 -o make.info make.texi; \
then \
  rc=0; \
  CDPATH="${ZSH_VERSION+.}:" && cd .; \
else \
  rc=$?; \
  CDPATH="${ZSH_VERSION+.}:" && cd . && \
  $restore $backupdir/* `echo "./make.info" | sed 's|[^/]*$||'`; \
fi; \
rm -rf $backupdir; exit $rc
/home/senooken/.local/src/make/config/missing: line 81: makeinfo: command not found
WARNING: 'makeinfo' is missing on your system.
         You should only need it if you modified a '.texi' file, or
         any other file indirectly affecting the aspect of the manual.
         You might want to install the Texinfo package:
         <http://www.gnu.org/software/texinfo/>
         The spurious makeinfo call might also be the consequence of
         using a buggy 'make' (AIX, DU, IRIX), in which case you might
         want to install GNU make:
         <http://www.gnu.org/software/make/>
make[1]: *** [Makefile:389: make.info] Error 127
make[1]: Leaving directory '/home/senooken/.local/src/make/doc'
make: *** [Makefile:797: install-recursive] Error 1

GNU Makeをリポジトリーからビルドする場合は,依存先が増え手順が複雑になるので注意する。

glibc 2.26以上でのコンパイルエラー対策

GNU Cライブラリーであるglibcのバージョンが2.26以上である場合,./build.shやmakeの実行時に以下のコンパイルエラーが発生する。

glob.o: In function `glob_in_dir':
/home/senooken/.local/src/make/./glob/glob.c:1367: undefined reference to `__alloca'
/home/senooken/.local/src/make/./glob/glob.c:1342: undefined reference to `__alloca'
/home/senooken/.local/src/make/./glob/glob.c:1256: undefined reference to `__alloca'
/home/senooken/.local/src/make/./glob/glob.c:1283: undefined reference to `__alloca'
glob.o: In function `glob':
/home/senooken/.local/src/make/./glob/glob.c:581: undefined reference to `__alloca'
glob.o:/home/senooken/.local/src/make/./glob/glob.c:732: more undefined references to `__alloca' follow
collect2: error: ld returned 1 exit status

glibcのバージョンは,glibcの同梱ソフトの一つのlddコマンドを使って以下のとおりに確認できる。

glibcのバージョン確認方法
ldd --versionldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27
Copyright (C) 2018 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.
Written by Roland McGrath and Ulrich Drepper.

この問題は以下で議論されている通り,2017-08-02にglibcのバージョンが2.26に上がり,内部のGLOBインターフェイスのバージョンが1から2に上がったことが原因だ。

On Sat, Nov 18, 2017 at 04:48:12PM -0500, Paul Smith wrote:
> One way to fix this would be to change the second #if line above to be:
>
> # if _GNU_GLOB_INTERFACE_VERSION >= GLOB_INTERFACE_VERSION
>
> and see if that works.

Yes! This solves the issue and it also solves the __stat issues as
well.

>
> Is there anywhere documented what the difference is between version 1
> and version 2? Is it just this symlink change? I’m not sure if the
> above change is absolutely correct since it means we’ll always accept
> the latest libc glob interface, which seems to defeat the purpose of
> having a version in the first place.

It seems to be a relatively recent change according to `git blame’.

https://sourceware.org/git/?p=glibc.git;a=commit;h=ccf970c7a77e86f4f5ef8ecc5e6

Apparently this patch committed in September 2017 to solve this bug
report:

https://sourceware.org/bugzilla/show_bug.cgi?id=22183

Within it someone mentions this beautiful gem:

* Bump _GNU_GLOB_INTERFACE_VERSION to 2 and forcing new GNUmake build to use its internal glob implementation.

Well, that sure backfired quite nicely, haha

Eamestly | Gnu – Make – Bugs – undefined reference to `__alloca’

この不具合は,2017-11-19のコミットで以下のように修正された。

glibc 2.26以上でのコンパイルエラー対策パッチ (48c8a116a914a325a0497721f5d8b58d5bba34d4)
diff --git a/configure.ac b/configure.ac
index 8c72568..4710832 100644
--- a/configure.ac
+++ b/configure.ac
@@ -404,10 +404,9 @@ AC_CACHE_CHECK([if system libc has GNU glob], [make_cv_sys_gnu_glob],
 #include <glob.h>
 #include <fnmatch.h>
 
-#define GLOB_INTERFACE_VERSION 1
 #if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
 # include <gnu-versions.h>
-# if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION
+# if _GNU_GLOB_INTERFACE_VERSION == 1 || _GNU_GLOB_INTERFACE_VERSION == 2
    gnu glob
 # endif
 #endif],

ただし,GNU Make 4.2.1は2016-06-10リリースである。GNU
Makeの次期リリース (4.2.2 or 4.3) ではこの不具合は解消されると思われる。GNU Make
4.2.1までは上記パッチが必要なので,インストール手順の18行目からインストール対象GNU Makeのバージョンをチェックし,4.2.1以下の場合は上記のパッチを適用している。

./make checkの失敗対策

前述のglib 2.26以上でのコンパイルエラー対策だけでは,実は対策が不十分だ。この場合,./make check実行時に以下のエラーが発生してテストに失敗する。

./make check実行時のエラー
functions/wildcard ...................................... Error running /home/senooken/.local/src/make/build/tests/../make (expected 0; got 139): /home/senooken/.local/src/make/build/tests/../make -f work/functions/wildcard.mk.1

Caught signal 11!
Error running /home/senooken/.local/src/make/build/tests/../make (expected 0; got 139): /home/senooken/.local/src/make/build/tests/../make -f work/functions/wildcard.mk.2

Caught signal 11!
FAILED (4/6 passed)

先程のglib 2.26以上でのコンパイルエラーと共に,この問題は「Re: Strange errors regarding function ‘__alloca’ on a Debian buster/sid」で報告されている。

この問題への対策は,GNU MakeのメインテナーであるPaul Smithにより回答されていた。以下の2017-10-30のコミットを取り込めばよいととのことだ。

./make check実行時エラーの対策パッチ (193f1e81edd6b1b56b0eb0ff8aa4b41c7b4257b4)
diff --git a/dir.c b/dir.c
index adbb8a9..c343e4c 100644
--- a/dir.c
+++ b/dir.c
@@ -1299,15 +1299,40 @@ local_stat (const char *path, struct stat *buf)
 }
 #endif
 
+/* Similarly for lstat.  */
+#if !defined(lstat) && !defined(WINDOWS32) || defined(VMS)
+# ifndef VMS
+#  ifndef HAVE_SYS_STAT_H
+int lstat (const char *path, struct stat *sbuf);
+#  endif
+# else
+    /* We are done with the fake lstat.  Go back to the real lstat */
+#   ifdef lstat
+#     undef lstat
+#   endif
+# endif
+# define local_lstat lstat
+#elif defined(WINDOWS32)
+/* Windows doesn't support lstat().  */
+# define local_lstat local_stat
+#else
+static int
+local_lstat (const char *path, struct stat *buf)
+{
+  int e;
+  EINTRLOOP (e, lstat (path, buf));
+  return e;
+}
+#endif
+
 void
 dir_setup_glob (glob_t *gl)
 {
   gl->gl_opendir = open_dirstream;
   gl->gl_readdir = read_dirstream;
   gl->gl_closedir = free;
+  gl->gl_lstat = local_lstat;
   gl->gl_stat = local_stat;
-  /* We don't bother setting gl_lstat, since glob never calls it.
-     The slot is only there for compatibility with 4.4 BSD.  */
 }
 
 void

こちらもインストール手順の18行目から,インストール対象のGNU Makeが4.2.1以下の場合にパッチを適用することで対応している。

なお,make check実行時にPERL_UNSAFE_INC=1を指定 (または事前にexport PERL_UNSAFE_INC=1を実行) しておかないと,以下のエラーが出るので注意する。

make[2]: Entering directory '/home/senooken/.local/src/make'
cd tests && perl ./run_make_tests.pl -srcdir /home/senooken/.local/src/make -make ../make
Can't locate test_driver.pl in @INC (@INC contains: /home/senooken/perl5/lib/perl5 /home/senooken/perl5/lib/perl5 /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.26.1 /usr/local/share/perl/5.26.1 /usr/lib/x86_64-linux-gnu/perl5/5.26 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.26 /usr/share/perl/5.26 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at ./run_make_tests.pl line 61.
make[2]: *** [Makefile:1281: check-regression] Error 2
make[2]: Leaving directory '/home/senooken/.local/src/make'
make[1]: *** [Makefile:1088: check-am] Error 2
make[1]: Leaving directory '/home/senooken/.local/src/make'
make: *** [Makefile:797: check-recursive] Error 1

make checkにPerlを使っているようで,外部ファイルを読み込んでいる。最近のPerlではセキュリティの観点から,環境変数が有効でないと,外部ファイルを読み込まないらしい。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です