Git の基礎概念 2
参考書籍
Gitとは
git はファイルの状態を管理するためのソフトウェア。
git で管理されているディレクトリ配下のファイル群のバージョン管理を行うことができる。
オブジェクト
git はオブジェクトという単位でデータを扱う。オブジェクトには下記の型がある。
- blob オブジェクト
- tree オブジェクト
- commit オブジェクト
- tag オブジェクト
オブジェクトはオブジェクトデータベース に保管されている。一意の名前で検索するので高速にアクセスできる。
オブジェクトは全て下記のような構造を持っている。
- 名前
- ヘッダ
- ボディ
名前はヘッダとボディをまとめてハッシュ化した文字列が与えられる。これによって一意性を担保している。
ヘッダにはオブジェクトの型種別とサイズが入っている。
ボディにはデータの内容が入っている。項目は型によって異なる。
blob オブジェクト
git で管理するファイル一つ分のデータに対応する。
blob オブジェクトのボディ
ファイルの中身が格納されている。
tree オブジェクト
git で管理するディレクトリ一つ分のデータに対応する。
tree オブジェクトのボディ
対応するディレクトリ直下のファイルやディレクトリのオブジェクト名のリストが格納される。
これによりトップレベルの tree オブジェクトから git 管理対象のファイル群の全てを再現することができる。
commit オブジェクト
コミット一つ分に対応する。
commit オブジェクトのボディ
コミットのメッセージや作成時間や作者が格納される。
これによっていつ誰がどういう意図でそのコミットが作られたのかを確認することができる。
その他 tree や parent という項目が記録されることでディレクトリ構成やプロジェクトの歴史を辿ることができる。
コミットオブジェクトの内容は下記のように確認できる。
git cat-file -p 6fe9eb78ab891c36a6d3b6b659e0d9f2a89545ee
tree
トップレベルの tree オブジェクトの名前。
これによりそのコミット の時点で git 管理するファイル群全てを再現することができる。
parent
一つ前のコミットのオブジェクト名。
これによりコミット間で親子関係を表現することができ、過去のコミットの歴史を辿ることができるようになる。
その他キーワード
ブランチ
ブランチとは特定のコミットへのポインタのこと。
ブランチ -> コミット
HEAD
HEAD とは現在チェックアウトしているブランチへのポインタのこと。
HEAD -> ブランチ -> コミット
マージ
マージするとマージコミット が作成される場合とそうでない場合がある。
マージする側が対象のブランチが分岐した時点から変化していない場合はマージコミットが作成されない。その場合はマージする側のブランチが対象のブランチのコミットと同じものになるだけ。これをfast forward
という。
マージコミットは parent を二つ持つ。
apt の基本
apt の基本
apt とは
apt
とは advanced packaging tool の略。
パッケージ管理のためのツールの一つ。
パッケージとはtmux
やtree
など便利なツールを実行ファイル・設定ファイル・ドキュメントなど一まとめにアーカイブしたファイルのこと。
リポジトリと呼ばれるパッケージを保管するためのサーバーで管理されている。
ディストリビューションごとに公式のリポジトリがあり、デフォルトのリポジトリとして設定されている。
公式以外のリポジトリもあり、設定を変えることでそれらからもパッケージを取得することができる。
apt の基本的な使い方
apt-get update、apt-get install、apt-get remove、apt-cache search、apt-cache show といった一部の人気コマンドが単に apt を経由して apt update、apt install、apt remove、apt search、apt show でもできるようになったということです。 apt ツールは apt-get と apt-cache の機能を統合し、デフォルトで小洒落た色付きの出力形式を採用して人間にとって使いやすくなっています。スクリプトでの利用や細かな処理には apt-get の方が好ましいあるいは必要となるでしょう。
apt
はapt-get/apt-cache
のラッパーぽい?
とりあえずはapt
を使っておけば良さそう。
# 例
apt search nkf
sudo apt install nkf
sudo apt remove nkf
パッケージ更新の流れ
apt update と apt upgrade
apt update
apt が使うことのできるパッケージのリストを更新する。これは新しいパッケージのインストールは行わない。
apt upgrade
apt が管理しているリストを基にインストール済みのパッケージのより新しいバージョンを取得しインストールする。
パッケージの更新
実際にパッケージを新しくするためには update で新しいバージョンの情報を取得してから upgrade でそのバージョンのインストールを行う必要がある。
sudo apt update && sudo apt upgrade
標準以外のソフトをインストール
- apt-get で見つからないパッケージを追加する方法(debian, ubuntu 両方対応)
- devian: パッケージ
- 【 apt-file 】コマンド――特定のファイルが収録されているパッケージを探す
apt-add-repository
でsources.list
にリポジトリを追加することができる。
$ sudo apt-add-repository non-free
$ cat /etc/apt/sources.list
# deb http://ftp.jp.debian.org/debian buster main
deb http://ftp.jp.debian.org/debian buster main non-free
deb-src http://ftp.jp.debian.org/debian buster main non-free
deb http://security.debian.org/debian-security buster/updates main non-free
deb-src http://security.debian.org/debian-security buster/updates main non-free
CSSで余白を作る時に親要素のpaddingにすべきか子要素のmarginにすべきかで迷う
前提(親子の位置関係)
- 要素の中身や指定がない場合、親要素のheightは子要素のそれと等しくなる。
- 要素の中身や指定がない場合、子ブロック要素のwidthは親要素のそれと等しくなる。幅の指定のある先祖がいない場合は window 幅になる。
- 親要素が要素の中身や border の実体を持っていなくて padding が指定されていない場合は子要素は親要素から見て
top: 0; left: 0
の位置に配置される。
子要素のmarginとして余白を作る
親要素が要素の中身や border の実体を持っていない場合
- 子要素の上下に margin が指定されていたとしても
top: 0
の位置は変わらない。 - 子要素の左右に margin が指定されている場合はそれが反映される。
- 親要素にoverflow: hidden;が設定された場合は子要素の margin は親要素との境界に対して適用される。ただし margin を適用させる目的でこれを行うべきではない。
親要素が要素の中身や border の実体を持っている場合
親要素が要素の中身や border の実体を持っている場合には子要素の margin はそれらに対して適用される。結果的に子要素の上下にmarginが適応される。
親要素のpaddingとして余白を作る場合
親要素に padding が指定されている場合は子要素常には padding の内側に配置される。
結論
子要素にmarginをつけて親要素との余白をとろうとすると条件によって適用のされ方に違いが出るので親要素にpaddingを設けた方が実装がシンプルになる場合が多い。
CSS のボックスモデルについて
CSS のボックスモデルについて
参考資料
ボックスモデルとは
CSS では要素の持つ領域についてボックスモデルと呼ばれる考え方が適用されている。
ボックスモデルとは html の要素がそれぞれボックス型の領域を持っていて CSS でその領域の大きさや他の要素(の境界)との距離を操作することができるというモデルである。
CSS でセレクタを指定して操作できるのはそのセレクタの属する領域についてである。
用語について
ボックスモデルでは要素の持つ領域がパーツに分けられている。
それぞれのパーツとその外側に名前がついているのでまとめる。
要素
要素は html の開始タグから終了タグまでの部分のこと。
この領域のことをcontent-box
と呼ぶと思われる。
height
やwidth
で指定できるのは要素そのものの値となる。
インライン要素のheight
やwidth
は固定されているため指定することができない。
要素そのものの大きさ(長さ)はその要素が持つ領域を超えることもできる。超えた部分の要素は他の要素の領域にも干渉する。
領域を超えた部分の扱いについてはoverflow
プロパティで指定することができる
padding
padding
は要素に属する領域(border-box
)のうち要素そのもの(content-box
)の外側の部分のこと。
border
border
は要素に属する領域とその外側の境界線のこと。
margin
margin によって要素に属している領域の外側の部分の余白(他の要素の境界との距離)を指定することができる。
margin 自体はその要素に属していないのでこの余白の指定は他の要素の指定に相殺されることがある。
box-sizing
box-sizing
プロパティを指定することによって width
やheight
で設定できる範囲を変更することができる。
上記の要素の説明は初期値であるbox-sizing: content-box;
に即している。
box-sizing: border-box;
とすればpadding
とborder
が含まれる領域についてwidth
やheight
を指定できるようになる。
CSS の基本
CSS の基本
参考資料
CSS とは
CSS とは Cascading Style Sheet の略。
CSS はスタイルシートの一つ。スタイルシートは文章の見た目を定義するための仕様のこと。
スタイルシートは HTML の誕生の前から存在していた。
HTML に適用することができるスタイルシートは CSS だけではない。
ただし一般的なブラウザに実装されているのは CSS であるため普通はこれを使用する。
CSS の書き方
p タグの文字列を青で表示する CSS。
p { color: blue; }
セレクタ
p
の部分({}
の前)のことをセレクタと呼ぶ。
スタイルを適用させたい対象をここに書く。
ここではp
要素を指定している。
宣言
{}
で括られた中身の部分のことを宣言と呼ぶ。
なかにプロパティと値を書く。
宣言は;
で区切って複数書く事ができる。
プロパティ
{}
内の:
の左側のcolor
の部分。
適用させたい表現の種類をここに書く。
ここではセレクタの文字列の色を指定しようとしている。
プロパティは定義されているものの中から選ぶ。
値
{}
内の:
の右側のblue
の部分。
プロパティを具体的にどのようにしたいのかを書く。
ここではセレクタの文字列の色を青色にしようとしている。
CSS はどこに書くか
HTML に CSS を適用するためにはブラウザが認識できる場所にそれが書かれている必要がある。
HTML 要素の style 属性で定義する
要素の属性情報として直接指定する。
style 属性の値として CSS の記法で文字列を指定する。
まさにその要素のみに適用される。
<span style="color: blue;">青い文字</span>
HTML の style 要素で定義する
head 要素内に書く。
HTML 内の全ての要素に対して適用される。
<head> <style type="text/css"> h1 { color: red; } </style> </head>
外部ファイルからの読み込み
CSS が書かれた CSS ファイル(.css)を用意する。
適用したい HTML のhead
要素内にlink
要素で定義して対象の css ファイルを読み込む。
<head> <link rel="stylesheet" type="text/css" href="common.css" /> </head>
CSS の優先順位
CSS ではある HTML 要素に対して複数の方法でスタイルを指定することができそれらは共存することができる。
これらが競合する場合には優先順位順にスタイルが適用される。また、同じ優先順位の CSS が競合している場合は読み込みの順番が遅いものが優先される。
自作コンパイラ開発メモ(2020/12/13)
低レイヤを知りたい人のための C コンパイラ作成入門を読んでコンパイラ自作してる時の作業記録です。
対象箇所
for 文に対応するアセンブリを出力できるようにしました。
実装
- 関数 foo が定義された c のプログラムを作成
- 関数名を識別子としてトークナイズ
- 関数としての node を生成できるようにした
- 関数の node を消費してアセンブリで指定の関数(foo)を呼び出せるようにした
- foo が定義されたプログラムを自分のコンパイラの出力とリンクできるようにした
- 生成された実行ファイルで foo が実行されることを確認した
メモ
primary = num | ident ("(" ")")? | "(" expr ")"
ident が変数名なのか関数名なのかは直後の()
の有無で判断する。
関数の node を消費してアセンブリで指定の関数(foo)を呼び出せるようにした
call foo
今回は擬似的に関数の呼び出しを確認するだけなので node を消費したときは引数なしのfoo
をcall
するようにした。
foo が定義されたプログラムを自分のコンパイラの出力とリンクできるようにした
./9cc "$input" > tmp.s cc tmp.s foo.c -o tmp ./tmp
tmp という実行ファイルを作成している。
tmp.s
は自分のコンパイラで出力したアセンブリでfoo.c
はfoo()
が定義されている c ファイルです。
cc
の引数にこれらの二つのファイルを渡すことで互いにリンクさせることができる。
自作コンパイラ開発メモ(2020/11/22)
低レイヤを知りたい人のための C コンパイラ作成入門を読んでコンパイラ自作してる時の作業記録です。
対象箇所
for 文に対応するアセンブリを出力できるようにしました。
実装
メモ
ブロックとは
正式には「compound statement」と呼ばれるらしい。
「compound」は複合という意味。直訳すると複合文となる。
複数の文をまとめて一つの意味のある処理と捉えることができる。
関数の本体部分もブロックである。
制御構文の{}と関数の{}には違いがない。
実装
EBNFにブロックを取り入れると下記のようになる。
program = stmt* stmt = expr ";" | "{" stmt* "}" | "if" "(" expr ")" stmt ("else" stmt)? | "while" "(" expr ")" stmt | "for" "(" expr? ";" expr? ";" expr? ")" stmt | "return" expr ";" | ... ...
ブロックは"{" stmt* "}"
の部分。
{
を検出したら}
が検出されるまでstmt
を消費する。
stmtの一回以上の繰り返し(stmt*
)はprogram = stmt*
ですでに実装したので同じ方法で実装した。
if (consume("{")) { int i = 0; node = new_node(ND_BLOCK, node, NULL); while (!consume("}")) { node->block[i++] = stmt(); } node->block[i] = NULL; }
Node構造体のメンバにblock
としてNodeのポインタの配列を宣言した。
Node *block[100];
ハマった箇所
最初Node *block[];
のようにNodeのblockの要素の数を指定していなかった。
そしたら、node->kindを参照する箇所で想定しない値が入っていてバグになっていた。
その値は実行する度に違う値になっていたので意図しないアドレスをしているはずだと思い、配列の要素数を指定してみたところ想定する動きになった。