sudo権限がない状態でローカルにパッケージや依存ライブラリをインストールする方法

共用のサーバなどでsudo権限がない状態でapt-get, yum, brewなどでパッケージをインストールしたいと思った時にpermission deniedで怒られたことは誰しもあると思います。
その時に自分のローカルの環境にインストールする際にいつもやり方を忘れてしまうので、流れをざっとまとめてみました。

ちなみにdockerを使って各イメージの用途に合わせて必要なパッケージをインストールすれば良い、という話もありますが、tmuxやscreenなどホスト側にインストールしたい場合もあると思うので知っておいて損はないはずです。

# 手順
1. 共有ライブラリのソースをダウンロード
2. 共有ライブラリをコンパイル、ローカルのフォルダにインストール
3. パッケージのソースをダウンロード
4. パッケージをコンパイル、ローカルのフォルダにインストール
5. インストールしたローカルのフォルダにパスを通す

以下でtmuxをローカルにインストールする方法を例に説明していきます。
ちなみにインストール方法は以下のページを参考にさせていただきました。
https://qiita.com/kentarosasaki/items/f6769109a251fcc96208

# 共有ライブラリのソースをダウンロード
共有ライブラリとは以下のサイトの言葉を引用すると、
https://www.weblio.jp/content/%E5%85%B1%E6%9C%89%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA

> 共有ライブラリとは、複数のプログラムが共通して利用する汎用性の高いプログラムの部品の集まりのことである。

です。通常、tmuxなどのパッケージには必要なライブラリが同梱されているのですが、汎用的なライブラリ(共有ライブラリ)についてはパッケージには含まれていません。tmuxでは「libevent(tmux-1.2以降で必要)」と「ncurses」が必要な共有ライブラリで且つubuntuやcentOSなどの環境でデフォルトで入っていないライブラリです。そのため、パッケージのインストール前にこれらの共有ライブラリをダウンロード＆インストールしておく必要があります。

ソースのダウンロードをする前にソースファイルを置くディレクトリを作りましょう。

```shell:terminal
mkdir -p ~/tools/src
```

次にlibeventをダウンロードします。
ちなみに、libeventはファイルディスクリプタに特定のイベントが生じた際にcallback関数を実行するイベント通知プログラムです。例えば、実行中のスクリプトが標準エラー出力に出力を開始した、などの特定のイベントが起きたことを瞬時に検知してそれをトリガーに別の処理を実行する、といった場合にイベント検知（通知）に使えます。

```shell:terminal
wget https://github.com/libevent/libevent/releases/download/release-2.1.8-stable/libevent-2.1.8-stable.tar.gz -P ~/tools/src
cd ~/tools/src
tar zxf libevent-2.1.8-stable.tar.gz
```

次にncursesをダウンロードします。ncursesはキー入力や画面表示など、端末のテキストユーザインタフェース(TUI)を作る際に使うライブラリです。

```shell:terminal
wget -nc ftp://ftp.invisible-island.net/ncurses/ncurses-6.1.tar.gz -P ~/tools/src
cd ~/tools/src
tar zxf ncurses-6.1.tar.gz
```

ちなみに、もはやwgetすらない場合はブラウザからftpサイトやgithubのサイトにアクセスしてダウンロードし、インストールしたい環境にscpなどで移してインストールすればOKです。本ページと同じ方法でwget自体もインストールできます。
また、ソースのリンクが消滅している場合もブラウザでソースのリンクを探してみましょう。
例えば、ncursesならgoogleで検索すると下記のリンクが出てきて、ソースのリンクが貼ってあることがわかるかと思います。
https://www.gnu.org/software/ncurses/

# 共有ライブラリをコンパイル、ローカルのフォルダにインストール
ここからは共有ライブラリのインストールです。
まずはインストールする前に、インストールするサーバやlaptopのOSや必要なライブラリが存在するかどうかをチェックしてMakefileを作成するconfigureスクリプトを実行します。

```shell:terminal
cd ~/tools/src/libevent-2.1.8-stable
./configure --prefix=${HOME}/tools
```

Makefileはソースコードをコンパイルする(つまりC言語などの人間が読める形のファイルを機械語に変換する)処理が記述されたファイルです。このMakefileにはconfigureファイルで指定されたパッケージのインストール先が記述されていますが、configureを実行する際に特に指定をしない基本的には「/usr/local」が指定されることになります。ところが/usr以下はsudo権限がないと書き込みができないため、このままだとインストール時にエラーが起きます。そこでconfigure実行時に--prefixをつけることでパッケージのインストール先をローカルの書き込み権限のあるフォルダに指定します。
prefixを指定するのではなくMakefileそのものを編集してインストール先を変更することもできます。

実行すると下記のように環境を確認して、config.statusにまとめ、Makefileなどのファイルを作成していることが確認できます。

```shell:terminal
checking for struct sockaddr_storage.__ss_family... no
checking for struct so_linger... no
checking for socklen_t... yes
checking whether our compiler supports __func__... yes
checking for the pthreads library -lpthreads... no
checking whether pthreads work without any flags... yes
checking for joinable pthread attribute... PTHREAD_CREATE_JOINABLE
checking if more special flags are required for pthreads... -D_THREAD_SAFE
checking size of pthread_t... 8
checking for library containing ERR_remove_thread_state... -lcrypto
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating libevent.pc
config.status: creating libevent_openssl.pc
config.status: creating libevent_pthreads.pc
config.status: creating libevent_core.pc
config.status: creating libevent_extra.pc
config.status: creating Makefile
config.status: creating config.h
config.status: creating evconfig-private.h
config.status: evconfig-private.h is unchanged
config.status: executing depfiles commands
config.status: executing libtool commands
```

Makefileには下記のような記載がありました。

```vim
prefix = /Users/danshari-ni/tools
```

私の環境では${HOME}=/Users/danshari-ni なので、configureのオプション--prefixで指定した値がMakefileにハードコードされていることがわかります。

次にmakeコマンドを使ってコンパイルを行います。

```shell:terminal
make
```

次にmake installを実行し、makeコマンドで生成されたバイナリファイルなどを--prefixで指定したディレクトリにコピーします。

```shell:terminal
make install
```

インストールが終わると~/tools配下にlib, bin, includeといったコンパイル済みのライブラリのファイルを格納するディレクトリが作成され、libevent関連のバイナリファイルが配置されています。

ちなみに、Mac OSXではmake実行時に下記のようなエラーが出てくるかもしれません。

```shell:terminal
bufferevent_openssl.c:66:10: fatal error: 'openssl/bio.h' file not found
```

その場合はconfigure実行時に下記を実行してください。

```shell:terminal
./configure --prefix=${HOME}/tools LDFLAGS="-L/usr/local/opt/openssl/lib" CFLAGS="-I/usr/local/opt/openssl/include"
```

同様にしてncursesもインストールします。

```shell:terminal
cd ~/tools/src/ncurses-6.1
./configure --prefix=${HOME}/tools
make
make install
```

# パッケージのソースをダウンロード

共有ライブラリの時と同様にwgetを使ってtmuxのソースファイルをダウンロードします

```shell:terminal
wget https://github.com/tmux/tmux/releases/download/2.6/tmux-2.6.tar.gz -P ~/tools/src
cd ~/tools/src
tar zxf tmux-2.6.tar.gz
```

# パッケージをコンパイル、ローカルのフォルダにインストール

configureを実行します。

```shell:terminal
cd ~/tools/src/tmux-2.6
./configure --prefix=${HOME}/tools LDFLAGS="-L${HOME}/tools/lib" CFLAGS="-I${HOME}/tools/include"
```

LDFLAGSはMakefileで記述するライブラリの場所で、今回インストールしたlibeventとncursesは~/tools/libに配置されているので、ここを指定します。

CFLAGSはMakefileで記述するインクルードファイルの場所で、今回インストールしたlibeventとncursesのインクルードファイルは~/tools/includeに配置されているので、ここを指定します。

ソースファイルをコンパイルしてインストールします。

```shell:terminal
make
make install
```

ちなみに私の環境では

```shell:terminal
curses.h not found 
```
のようなエラーが出たので、~/tools/includeを見るとncursesという名のディレクトリが作成されていて、この中にcurses.hが入っていました。これらのファイルを~/tools/include/にmvで移動するとインストール時にエラーが出なくなりました。

# インストールしたローカルのフォルダにパスを通す

最後にパッケージと共有ライブラリのパスを通します。~/.bash_profileに下記を追記してください。

```vim:.bash_profile
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${HOME}/tools/lib # libeventなどの共有ライブラリへのパスを通す
export PATH=$PATH:/home/nakamura/tools/bin #ローカルにインストールしたパッケージへパスを通す
```

以上でsudo権限がない状態でローカルにパッケージや依存ライブラリをインストールできました。