---
title: 使用Makru和makru_langc管理现代C项目编译： 配置Makru和makru_langc
date: 2021-01-04 18:49:20
updated: 2021-01-18 16:37:00
tags:
  - Makru
  - C
categories: 代码农场
---

在这一篇文章中，我会介绍makru_langc的安装。和普通的编译工具不同，makru_langc是作为Makru的一个插件安装的，而Makru的插件只能安装到项目上随项目源代码附带。这会带来一些不方便，但是能够保证每一个项目都能选择最适合的插件和插件版本而无需担心兼容成本。其实类似的方法在make和cmake的项目中也能经常看见，很多项目都会带有一些脚本或者预定义宏来帮助编译，只是Makru将它变成强制行为了。

<!-- more -->

这是一篇属于“使用Makru和makru_langc管理现代C项目编译”系列的文章，你可以在{% post_link makru-tutor-1 %}找到目录。

注意：makru_langc尚未考虑对于Windows的支持。

## 安装Makru
Makru完全由Python编写而成，只需要你有Python。目前对于Python低版本的兼容性未知，但是你至少应该有3.6或更高版本的Python。我的环境使用的是Python 3.9.1。

如果你不想在系统级别安装Makru，你可以使用[virtualenv](https://pypi.org/project/virtualenv/)创建一个目录级的Python虚拟环境。不过其实一般情况下你不需要这样做。

````
$ pip install makru
Collecting makru
  Downloading makru-0.1.0b14-py3-none-any.whl (12 kB)
Collecting semver<3.0.0,>=2.13.0
  Downloading semver-2.13.0-py2.py3-none-any.whl (12 kB)
Collecting pluginbase<2.0.0,>=1.0.0
  Downloading pluginbase-1.0.0.tar.gz (41 kB)
     |████████████████████████████████| 41 kB 573 kB/s 
Collecting PyYAML<6.0.0,>=5.1.1
  Downloading PyYAML-5.3.1.tar.gz (269 kB)
     |████████████████████████████████| 269 kB 1.1 MB/s 
Building wheels for collected packages: pluginbase, PyYAML
  Building wheel for pluginbase (setup.py) ... done
  Created wheel for pluginbase: filename=pluginbase-1.0.0-py3-none-any.whl size=7747 sha256=7f4d815404165862e1c1a5544f115e566dd375355bb1caba1769b27be4d30f9a
  Stored in directory: /tmp/pip-ephem-wheel-cache-aisr91om/wheels/a6/31/1d/6f541ab6fdbb2e3fce5472e65c9769ecb782428d22d68ad938
  Building wheel for PyYAML (setup.py) ... done
  Created wheel for PyYAML: filename=PyYAML-5.3.1-cp39-cp39-linux_x86_64.whl size=44617 sha256=184ba6ba623bfa178270185f0afd6ba1ef695f08bb3f0298303ed87a665dc6e5
  Stored in directory: /tmp/pip-ephem-wheel-cache-aisr91om/wheels/69/60/81/5cd74b8ee068fbe9e04ca0d53148f28f5c6e2c5b177d5dd622
Successfully built pluginbase PyYAML
Installing collected packages: semver, pluginbase, PyYAML, makru
Successfully installed PyYAML-5.3.1 makru-0.1.0b14 pluginbase-1.0.0 semver-2.13.0
````
可以看到Makru非常小，包含依赖在内只需要600KB左右。

让我们随便运行一下：
````
$ makru
panic: could not found /some/random/path/makru.yaml.
````
好了，看起来Makru装好了。虽然它在抱怨在当前目录下面找不到配置文件，但是我们需要继续向前。配置文件是下一篇博文的问题。

## 安装makru_langc

还记得在文章第一段我提到的事情吗？“Makru的插件只能安装在项目上随源代码附带”。其实意思就是说Makru不存在能在整个系统或用户上生效的插件，所有插件的作用范围仅限于该项目。所以我们并不需要真正地“安装”makru_langc，只需要将它放在指定的文件夹下面就会生效，默认情况下这个目录是`<你的项目>/makru/plugins`。

现在我们给我们即将到来的scat项目创建一个文件夹，就叫`makru-tutor`。在文章里的完整路径是`/path/to/makru-tutor`，所以我们的默认插件目录就是`/path/to/makru-tutor/makru/plugins`。

### 直接放置源代码安装
让我们直接开始吧！访问 [makru_langc的仓库](https://gitlab.com/jinwa/makru_langc)，点击下载按钮然后选择合适的压缩包格式。把里面包含`__init__.py`的所有文件解压到`/path/to/makru-tutor/makru/plugins/makru_langc`下。

{% img /img/makru-tutor/2/screenshot-download-makru-langc-source.png "直接点击页面上很明显的下载按钮就可以选择压缩包格式了" %}

列出makru_langc文件夹的文件列表，要看见`__init__.py`才是正确的放法：
````
$ ls /path/to/makru-tutor/makru/plugins/makru_langc
__init__.py
...其它文件
````

这样就安装好了！

但这篇文章还不应该结束，设想一下：大部分情况下升级插件都不会破坏兼容性，如果你想要享受最新功能和bug修复，每一次更新你都重复下载-解压的操作，这种重复性的操作让人感觉不便。我们还需要一个新的方案。
如果你使用Git来管理你的项目，这里有一个更方便的方法：Git子模块。
### 通过Git子模块安装
让我们看看Git子模块的简单解释：

{% quote "Pro Git, the 2nd edition" https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97 "7.11 Git 工具 - 子模块" %}
有种情况我们经常会遇到：某个工作中的项目需要包含并使用另一个项目。 也许是第三方库，或者你独立开发的，用于多个父项目的库。 现在问题来了：你想要把它们当做两个独立的项目，同时又想在一个项目中使用另一个。

我们举一个例子。 假设你正在开发一个网站然后创建了 Atom 订阅。 你决定使用一个库，而不是写自己的 Atom 生成代码。 你可能不得不通过 CPAN 安装或 Ruby gem 来包含共享库中的代码，或者将源代码直接拷贝到自己的项目中。 如果将这个库包含进来，那么无论用何种方式都很难定制它，部署则更加困难，因为你必须确保每一个客户端都包含该库。 如果将代码复制到自己的项目中，那么你做的任何自定义修改都会使合并上游的改动变得困难。

Git 通过子模块来解决这个问题。 子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中，同时还保持提交的独立。
{% endquote %}

这正是我们需要的！实话说，我在使用Git两三年之后才接触到这个特性，我相信很多人从来没使用过它。不过它确实在一些情况下很有用，比如现在我们的情况。

好吧，废话少说。如果你需要Git的子模块功能的话你需要先把目录变成一个仓库。我们可以使用Git的魔法咒语来完成这件事：
````
$ git init
已初始化空的 Git 仓库于 /path/to/makru-tutor/.git/
````

然后再使用一个魔法咒语（你不需要自己手动创建`makru/plugins`文件夹，Git会帮你打理好这些）：
````
$ git submodule add https://gitlab.com/jinwa/makru_langc.git makru/plugins/makru_langc
正克隆到 '/path/to/makru-tutor/makru/plugins/makru_langc'...
remote: Enumerating objects: 244, done.
remote: Counting objects: 100% (244/244), done.
remote: Compressing objects: 100% (137/137), done.
remote: Total 250 (delta 145), reused 183 (delta 104), pack-reused 6
接收对象中: 100% (250/250), 43.23 KiB | 48.00 KiB/s, 完成.
处理 delta 中: 100% (146/146), 完成.
````

然后就可以在相应目录下看到我们的插件：

````
$ ls /path/to/makru-tutor/makru/plugins/makru_langc
__init__.py
...其它文件
````
（如果你有过Python编程的经验，到这里你应该就明白为何makru_langc要采取这种奇怪的项目布局了）

但是到这里事情还没完，我们还需要一个提交把我们的子模块放进树里。如果你需要了解Git，你可以看看上面引用的那本《Pro Git》，这本书有中文翻译。
现在运行`git status`会多出来两个东西：
````
$ git status
位于分支 master

尚无提交

要提交的变更：
  （使用 "git rm --cached <文件>..." 以取消暂存）
        新文件：   .gitmodules
        新文件：   makru/plugins/makru_langc
````

要提交变更可以这样做：
````
git commit -m"随意产生的无意义信息（不"
````
所以我要这样：
````
$ git commit -m"add makru_langc to makru-tutor"
[master（根提交） 0ed585d] add makru_langc to makru-tutor
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 makru/plugins/makru_langc
````
然后安装就完成了！

不过，到这里我们仅仅是“做了件事”安装了Makru和makru_langc，还没看到任何反馈。别担心，下一篇文章里我们就会得到点反馈了。

下一篇文章：为可执行文件项目编写配置文件
