---
# System prepended metadata

title: BUILDFLAG
tags: [Chromium-General, elkurin-daily-note]

---

# BUILDFLAG

Chromiumはいろんなプラットフォーム上で動くように実装されている。  
中にはプラットフォームごとに実装を切りける必要がある。  

[BUILDFLAG](https://source.chromium.org/chromium/chromium/src/+/main:build/buildflag.h;l=45;drc=50487bd48e946a090749d6506318e4762f6c2a74)とはプラットフォームごとや各フラグごとに実装を変えたいときに使用されるマクロ。  
ファイルを変えてプラットフォームごとにincludeをかえることもでき、実際その手法もChromiumではよく出てくるが、ほぼ同じで一部変えたいときはクラスやファイルを分けるよりコード中にifdefフラグをいれるほうが良いケースが多い。

## 使用例
以下のような感じ。
```cpp=
#if BUILDFLAG(IS_CHROMEOS_ASH)
AshImpl();
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
LacrosImpl;
#else
NOTREACHED();
#endif
```
BUILDFLAGに渡せる引数は決まっており、IS_MACやIS_WINなどOSなこともあるし、IS_CHROME_BRANDEDというChromiumなのかGoogle産のChromeなのかを切り替えるものもあるし、いろいろある。

## 内部実装
この内部実装は

```cpp=
#define BUILDFLAG_CAT_INDIRECT(a, b) a ## b
#define BUILDFLAG_CAT(a, b) BUILDFLAG_CAT_INDIRECT(a, b)

#define BUILDFLAG(flag) (BUILDFLAG_CAT(BUILDFLAG_INTERNAL_, flag)())
```
`##`はMACROで主に使われる、トークンを連結する演算子。  
なのでやっていることは`BUILDFLAG_INTERNAL_`に`flag`をひっつけているだけの関数を呼んでいる。  
`BUILDFLAG_CAT_INDIRECT`と`BUILDFLAG_CAT`が2段階ふまれているのは、`##`を直接呼ぶと引数が展開されてしまうから。

では`BUILDFLAG_INTERNAL_`とはなにか？  
これは[build_config.h](https://source.chromium.org/chromium/chromium/src/+/main:build/build_config.h;drc=c964de601a7fdd237e3df1fd99b96c94b2c4fb84)にある。  

```cpp=
#if defined(OS_CHROMEOS)
#define BUILDFLAG_INTERNAL_IS_CHROMEOS() (1)
#else
#define BUILDFLAG_INTERNAL_IS_CHROMEOS() (0)
#endif
```
こんな感じでflag名と合体して1or0を変える関数になる。  
つまり、BUILDFLAG(flag)を呼ぶとflagがあるかどうかで0,1が帰ってくるので期待通り動く。

なお[defined](https://gcc.gnu.org/onlinedocs/cpp/Defined.html)は引数がマクロでdefineされているかどうかを返す。  
OS_CHROMEOSがdefineされているのは[BUILD.gn](https://source.chromium.org/chromium/chromium/src/+/main:build/config/linux/BUILD.gn;l=40;drc=54d7c782852ccf1e1b38c4dbe90d419022753e1e)の中
```
if (is_chromeos) {
  defines = [ "OS_CHROMEOS" ]
}
```