Closed10

書籍「ふつうのLinuxプログラミング」の学習記録

志水 亮介 (Ryosuke Shimizu)志水 亮介 (Ryosuke Shimizu)

始めた理由

これに影響されて、Linuxの勉強をしようと思った。

https://note.com/takkun_desu/n/n7297b6ea03ff

明確な理由はない。フレームワークだけ使いこなせるエンジニアじゃなくてシステムの低いレイヤーの理解度がある、汎用性の高いエンジニアになりたいから勉強しようと思いました。

フロントエンドエンドエンジニアなら、本当は

umdeyとかで、TSやNext.jsで動きのあるサイト作るのがいいのかもしれませんが、僕はLinuxを勉強する。

参考書籍

https://www.amazon.co.jp/dp/B075ST51Y5

Amazon.co.jp: ふつうのLinuxプログラミング 第2版 Linuxの仕組みから学べるgccプログラミングの王道 eBook : 青木 峰郎: 本

志水 亮介 (Ryosuke Shimizu)志水 亮介 (Ryosuke Shimizu)

環境構築

下記のレポジトリに作成した。

https://github.com/ryosuketter/linux_programming

下記のような感じで作成した。

https://github.com/ryosuketter/linux_programming/commit/e42e2d85c52dec5ee5cc47b23d5015438b40a7ad

Dockerfile

FROM ubuntu:latest

RUN mkdir /root/workspace

WORKDIR /root/workspace

RUN apt-get update -y --fix-missing \
    && apt-get install -y --no-install-recommends \
    sudo \
    build-essential \
    git \
    vim \
    man \
    manpages-dev \
    strace \
    gdb \
    tree \
    psmisc \
    net-tools
  • FROMは ubuntu最新版と指定
  • RUNは コマンドの実行、実際にRUNの右側に書いてあるのは読んで字の如くですね
  • WORKDIRは 作業ディレクトリ

apt-getコマンドとは

Debian系のディストリビューション(DebianやUbuntu)のパッケージ管理システムであるAPT(Advanced Package Tool)ライブラリを利用してパッケージを操作・管理するコマンドです。

apt-get updateはパッケージリストの更新です。

option

-y

インタラクティブ(ユーザーへの問い合わせ)に「yes」と答えます。

--fix-missing

ローカル環境のインデックスファイルが、サーバ上のインデックスファイルより古くても、無視して最後まで処理を続けるようです。

apt-get installはパッケージのインストール/更新をしています。

デフォルトだと recommends しているだけの必須ではないパッケージも一緒に入って時間がかかるので --no-install-recommends をつけるのが常套手段

http://blog.livedoor.jp/sonots/archives/50115456.html

らしいので、つけた。

という感じで、sudogitなどを追加しています。

docker-compose.yml

version: "3"

services:
  ubuntu:
    build:
      context: .
      dockerfile: ./Dockerfile
    container_name: "ubuntu"
    environment:
      TZ: Japan
    security_opt:
      - seccomp:unconfined
    volumes:
      - ./workspace:/root/workspace
    working_dir: "/root/workspace"

今回、コンテナは1つ作成(コンテナ名 ubuntu)。

こうすれば、

$ docker-compose build

これで、イメージがビルドされます。

ファイルを変更した際もまずビルドします。

security_opt

各コンテナに対するデフォルトのラベリング・スキーマ(labeling scheme)を上書きします。

http://docs.docker.jp/v1.12/compose/compose-file.html#security-opt

volumes

volumes に名前をつけて定義された /workspaceという名前の volume を、コンテナ内のディレクトリ /root/workspace にマウントしています。

working_dir

コンテナ内のワーキングディレクトリ。docker run コマンドの-w/--workdir に相当


docker-composeからDockerfileを実行するようにしている。

そうすると、レジストリからイメージ(ubuntu)を取得して、コンテナを作成。

コンテナの起動の仕方

次のコマンドは ubuntuを起動するためのコマンドです。

サービス内で bash としてコマンドを実行します。

$ docker-compose run ubuntu bash

run コマンドを使うと、サービスの設定ファイルで定義された通りに、同じ設定の新しいコンテナを開始します。

志水 亮介 (Ryosuke Shimizu)志水 亮介 (Ryosuke Shimizu)

gccを使ったビルド

10pあたりを学習

コンテナ名ubuntuを起動する

$ docker-compose run ubuntu bash

ホストOS上からエディタを使って

#include <stdio.h>

int main(int argc, char *argv[])
{
  printf("heloo!!!\n");
  return 0;
}

ビルドします

$ gcc hello.c

gccはlinuxで一般的に用いられるコンパイラ

a.out←ができている。gccに何もオプションをつけない場合、a.outという名前で作成するらしい。

# gcc hello.c

# ls
a.out  hello.c

実行してみる。

./をつける必要があるらしい。

# ./a.out
heloo!!!

成功した。

志水 亮介 (Ryosuke Shimizu)志水 亮介 (Ryosuke Shimizu)

14p

gcc -o hello hello.c

オプションoで生成されるファイル名を指定できる。

16p

gcc -Wall

https://www.unixuser.org/~euske/doc/gccopts/

にある警告オプションをすべて有効にする。 デバッグ中は、これを使うといいらしい。

gcc -o

gcc -Oは、コンパイラの最適化レベルを設定します。

-O2をつけるのがいいらしい。

https://www.rapidtables.org/ja/code/linux/gcc/gcc-o.html

コマンドライン引数

コマンドライン引数とはmain 関数の引数のことです。

workspace/args.c

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  int i;
  printf("argc=%d\n", argc);
  for(i=0; i<argc; i++){
    printf("argv=[%d]=%s\n", i, argv[i]);
  }
  exit(0);
}
$ gcc args.c -o args

コンパイル後、実行

./args x y z a c v
argc=7
argv=[0]=./args
argv=[1]=x
argv=[2]=y
argv=[3]=z
argv=[4]=a
argv=[5]=c
argv=[6]=v

コマンドライン引数とは x y zのことです。

つまり、コマンドライン引数とはmain 関数の引数のことです。

実行するときに、 コマンドラインからコマンドライン引数に値を与えることができます。

main(int argc, char *argv[]){...}

main関数の引数として、受け取っていたやつですね。

  • argcは渡された引数の数
    • argc: "argument count"(引数の個数)の略
  • argv
    • argv: "argument vector"(引数の配列)の略
    • 引数文字列の"配列へのポインタ"のことを指しているらしい

argv[0]は常に、プログラムが起動された時の名前が入っています。

なぜだろう?

コマンドライン引数はargv[1]から始まります。

志水 亮介 (Ryosuke Shimizu)志水 亮介 (Ryosuke Shimizu)

第二章「Linuxカーネルの世界」やってます。座学的な内容が多いから、ここに書くことない。

この書籍でいうところの重要概念である

  • ファイルシステム
  • プロセス
  • ストリーム

を学んだ

志水 亮介 (Ryosuke Shimizu)志水 亮介 (Ryosuke Shimizu)

catコマンドを作る

一応、本に習ってLinuxコマンドcatの内部処理を書いてみたが、理解ができているかどうか不明。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

static void do_cat(const char *path);
static void die(const char *s);

int
main(int argc, char *argv[])
{
  int i;

  if(argc < 2) {
    // argv[0]はプログラムの名前
    fprintf(stderr, "%s: file name not given\n", argv[0]);
    exit(1);
  }
  // indexを1から始めていることに注意
  for(i=1; i < argc; i++){
    // 引数はコマンドライン引数で渡されたファイル名
    do_cat(argv[i]);
  }
  exit(0);
}

#define BUFFER_SIZE 2048

static void
do_cat(const char *path)
{
  int fd;
  unsigned char buf[BUFFER_SIZE];
  int n;

  fd = open(path, O_RDONLY);
  if(fd < 0) die(path);
  for(;;){
    n = read(fd, buf, sizeof buf);
    if(n < 0) die(path);
    if(n == 0) break; // ファイルの読み込みが終わったらbreak
    if(write(STDOUT_FILENO, buf, n) < 0) die(path);
  }
  if(close(fd) < 0) die(path);
}

static void
die(const char *s)
{
  perror(s);
  exit(1);
}

コンパイルもできた。

$ gcc cat.c

:~/workspace# ls
a.out  args  args.c  cat.c  hello  hello.c

ただなんのためにやっているか段々わからなくなってきた。まだ続ける。

このスクラップは2023/03/18にクローズされました