2025年2月26日水曜日

Gnu C リンカ

 Gnu C Linker めおめも

https://qiita.com/seriru13/items/c2f5192615162c4c3f47   参照


gcc コンパイルオプション備忘録


参考サイト

gccコンパイラの使い方
江添亮のC++入門
リンカの役割 自分メモメモ
[C言語] 共有ライブラリと動的ライブラリを整理する

実行環境

  • Ubuntu 16.04 LTS
  • gcc 5.4

a.outを作る

$ gcc main.c

gcc が main.c を処理し、 a.out という実行ファイルが作られる。

実行ファイルに名前をつける

$ gcc main.c -o main

実行ファイルに名前をつけるときは -o オプションを使う。
実行後、 main という名前の実行ファイルが作られる。

複数のファイルから実行ファイルを作る

$ gcc main.c hello.c -o main

main.c hello.c という2つのファイルから main という実行ファイルを作る。

※ 例

main.c
#include <stdio.h>

void f();

int main() {
  f();
}
hello.c
#include <stdio.h>

void f() {
  printf("hello\n");
}

上記のコマンドでこの2つのファイルをコンパイルして、 ./main を実行すると

$ hello

と出力される。

オブジェクトファイルを作る

オブジェクトファイルはコンパイルはしたがリンクが終わっていない状態のファイルのこと。
gccでは以下のステップを踏んで実行ファイルが作られる。

  • プリプロセッサ
    • コンパイルを行う前にソースコードに対して行われる前処理
    • c/c++では, ディレクティブ(# ...)という命令を処理する。
ディレクティブの例
#include
#define
#if
#ifndef
#elif
#endif

などなど...
  • コンパイル

    • ソースコードをチェックして、中間言語や機械語に翻訳する。
  • リンク

    • オブジェクトファイルやライブラリを連結して、実行ファイルを作る。

例えば、 hello.c というファイルをオブジェクトファイルにするときは -c オプションを使用する。

$ gcc -c hello.c

これを実行することで hello.o というオブジェクトファイルが作られる。

もちろん複数ファイルも指定できる。

$ gcc -c a.c b.c

これで a.o b.o ができた。

複数のオブジェクトファイルから実行ファイルを作る

a.c b.c c.c というソースコードから以下のコマンドを使用して main という実行ファイルを作るとする。

$ gcc a.c b.c c.c -o main

その後、 a.c を変更したので main を更新したくなった。
しかし、main を更新するために上記コマンドを実行すると変更していない b.c c.c も再びコンパイルすることになり二度手間である。

そういうときにはすでにコンパイル済みのオブジェクトファイルを使うことができる。

$ gcc a.c b.o c.o -o main

これで実行ファイル main ができた。

静的ライブラリをリンクする -L

静的ライブラリとは libxxx.a のようなファイルのこと。
オブジェクトファイルの集合体で、 ar コマンドを使用して以下のように作成する。

ar -r libsample.a a.o b.o c.o

※ nm コマンドとか使うと色々中身が見れる。aファイル作成前のoファイルと比較すると面白いかも?

静的ライブラリもオブジェクトファイルの集合体だから、実行ファイルを作成するときに使用することができる。
ただしコンパイル時に静的ライブラリがあるディレクトリを -L オプションで指定する必要がある。

例えば、

---
 |- a.c
 |- b.c
 |- libsample.a 

というディレクトリ構成で, a.c b.c libsample.a から実行ファイル main を作るときは以下のようにしてディレクトリと静的ライブラリを指定する。

$ gcc a.c b.c -L. -lsample -o main

静的ライブラリは -lxxx の形で指定する。lib.a の部分は省略することができる。

(ここから少し怪しいです...)

-Lで静的ライブラリが存在するディレクトリを指定すると書いたが、 算術用ライブラリ libm.a は

$ gcc a.c -lm -o main

のように -L オプションなしで使用できる。
これは、リンカがデフォルトでライブラリを探しにいくディレクトリが決まっているからである。

これは ld --verbose でリンカスクリプトを見ると書いてある。

参考: リンカの役割 自分メモメモ

ヘッダを追加 -I

c/c++言語でヘッダファイルをインクルードする際には #include ディレクティブを使用する。

このときヘッダファイルの指定には以下の2つ方法がある。

ヘッダファイルの指定方法
#include <stdio.h> 
#include "stdio.h"

<...> と "..." の違いはコンパイラがヘッダファイルを探しにいくディレクトリのパスである。

<...> はデフォルトで指定されているパスを参照してヘッダファイルを探す。
"..." はデフォルトで指定されているパスに加えて "..." 内に書かれたパスにもヘッダファイルを探しにいく。

コンパイラがデフォルトで参照するパスは -v オプションを使用して、コンパイル処理の各段階において実行されたコマンドを出力することによって確認するのが手っ取り早い。

例えば、次の出力は ubuntu 16.04LTS で gcc -v xxx.c を実行させたときの一部である。

COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86-64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu

... 省略 ...

#include "..." search starts here:
#include <...> search starts here:
  /usr/include/c++/5
  /usr/include/x86_64-linux-gnu/c++/5
  /usr/include/c++/5/backward
  /usr/local/include

... 省略 ...

しかし、毎回ヘッダファイルの指定に #include "..." を使うのはパスをハードコーディングすることになり、色々面倒だ。

その時に使用するのが -I オプションである。
-I オプションを使用すると、 コンパイラが参照するパスに -I で指定したパスを追加してくれる。

次の出力は、 gcc -I../ -v xxx.c を実行したものである。

COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86-64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu

... 省略 ...

#include "..." search starts here:
#include <...> search starts here:
  ../
  /usr/include/c++/5
  /usr/include/x86_64-linux-gnu/c++/5
  /usr/include/c++/5/backward
  /usr/local/include

... 省略 ...

しっかりと <...> にパスが追加されている。
これで #include <...> で自作のヘッダが追加できるようになった。

-Wall, -W

  • バグかもしれない部分に警告を出してくれる。

-std=c++11, 14, 17, ...

  • それぞれ, c++11, c++14, c++17の機能を有効にする。
    • C++は3年に1回新しい国際基準が更新されるため、C++20なら, -std=c++20のように追加されていくでしょう。
    • 参考: 処理系

-O1, -O2, -O3, -Os


2025年2月6日木曜日

whl python ライブラリ 非インターネット

 


インターネットに接続できない環境で、Wheelファイルを使用することでPythonのパッケージのインストールが可能です。
今回は、IGWがアタッチされていない環境でEC2に、boto3をインストールします。

まとめ

  • pipを使わずに、whlファイルを使ってインストールします。

概要

Wheelファイルとは?

PEP427を参照すると、以下のように書かれています。

wheel は、特別な形式のファイル名と .whl 拡張子を持つ ZIP 形式のアーカイブです。特定のインストールスキームで PEP 376 に従ってインストールされるのとほぼ同じ単一のディストリビューションが含まれています。専用のインストーラーが推奨されますが、標準の「unzip」ツールを使用してサイト パッケージに展開するだけでホイール ファイルをインストールできます。

  • Wheelは、ZIP形式のアーカイブのこと。拡張子は、「.whl」。

実践

インターネットが繋がるPC上で、whlファイルをダウンロードし一旦S3に配置後、EC2からダウンロードしインストールします。

whlファイルのダウンロード

インターネットが繋がるPCで、boto3と関連するファイルをダウンロードし、S3にアップロードします。

curl https://files.pythonhosted.org/packages/23/d8/3b41ce8c96dedbb449f24de21eee0742786f414fea176f984b1101154f30/boto3-1.24.84-py3-none-any.whl -O
curl https://files.pythonhosted.org/packages/36/32/6ddb12143e32535550263514875db6d1a3ad50daf1377fbb1aac03a000aa/botocore-1.27.84-py3-none-any.whl -O
curl https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl -O
curl https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl -O
curl https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl -O
curl https://files.pythonhosted.org/packages/6f/de/5be2e3eed8426f871b170663333a0f627fc2924cc386cd41be065e7ea870/urllib3-1.26.12-py2.py3-none-any.whl -O

aws s3 cp boto3-1.24.84-py3-none-any.whl s3://${バケット名}/ec2/
aws s3 cp botocore-1.27.84-py3-none-any.whl s3://${バケット名}/ec2/
aws s3 cp jmespath-1.0.1-py3-none-any.whl s3://${バケット名}/ec2/
aws s3 cp python_dateutil-2.8.2-py2.py3-none-any.whl s3://${バケット名}/ec2/
aws s3 cp six-1.16.0-py2.py3-none-any.whl s3://${バケット名}/ec2/
aws s3 cp urllib3-1.26.12-py2.py3-none-any.whl s3://${バケット名}/ec2/

インストール

EC2にログインし、先程、アップロードしたファイルをS3からダウンロード後、インストールします。

aws s3 cp s3://${バケット名}/ec2/boto3-1.24.84-py3-none-any.whl /home/ssm-user/
aws s3 cp s3://${バケット名}/ec2/botocore-1.27.84-py3-none-any.whl /home/ssm-user/
aws s3 cp s3://${バケット名}/ec2/mespath-1.0.1-py3-none-any.whl /home/ssm-user/
aws s3 cp s3://${バケット名}/ec2/python_dateutil-2.8.2-py2.py3-none-any.whl  /home/ssm-user/
aws s3 cp s3://${バケット名}/ec2/six-1.16.0-py2.py3-none-any.whl  /home/ssm-user/
aws s3 cp s3://${バケット名}/ec2/urllib3-1.26.12-py2.py3-none-any.whl  /home/ssm-user/


sh-4.2$ pwd
/home/ssm-user
sh-4.2$ ls -l
total 9528
-rw-r--r-- 1 ssm-user ssm-user  132500 Oct  1 15:13 boto3-1.24.84-py3-none-any.whl
-rw-r--r-- 1 ssm-user ssm-user 9189276 Oct  1 15:46 botocore-1.27.84-py3-none-any.whl
-rw-r--r-- 1 ssm-user ssm-user   20256 Oct  1 15:53 jmespath-1.0.1-py3-none-any.whl
-rw-r--r-- 1 ssm-user ssm-user  247702 Oct  1 15:58 python_dateutil-2.8.2-py2.py3-none-any.whl
-rw-r--r-- 1 ssm-user ssm-user   11053 Oct  1 16:05 six-1.16.0-py2.py3-none-any.whl
-rw-r--r-- 1 ssm-user ssm-user  140381 Oct  1 16:09 urllib3-1.26.12-py2.py3-none-any.whl
sh-4.2$

pip3 install  --no-deps ./boto3-1.24.84-py3-none-any.whl
pip3 install  --no-deps ./botocore-1.27.84-py3-none-any.whl
pip3 install  --no-deps ./mespath-1.0.1-py3-none-any.whl
pip3 install  --no-deps ./python_dateutil-2.8.2-py2.py3-none-any.whl
pip3 install  --no-deps ./six-1.16.0-py2.py3-none-any.whl
pip3 install  --no-deps ./urllib3-1.26.12-py2.py3-none-any.whl

sh-4.2$ pip3 list
Package           Version
----------------- -------
aws-cfn-bootstrap 2.0
boto3             1.24.84
botocore          1.27.84
docutils          0.14
jmespath          1.0.1
lockfile          0.11.0
pip               20.2.2
pystache          0.5.4
python-daemon     2.2.3
python-dateutil   2.8.2
setuptools        49.1.3
simplejson        3.2.0
six               1.16.0
urllib3           1.26.12
sh-4.2$

考察

インターネットに繋がらない環境で、環境を構築することはたまにあります。
忘れないようにメモとして残しておきます。