Skip to content

Commit

Permalink
Add CHN Readmes, fix some errors in Readmes.
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNetAdmin committed Jul 21, 2017
1 parent 8071cba commit 4ac7ccb
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 3 deletions.
17 changes: 17 additions & 0 deletions BigProject/Readme-cn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 大型工程的Makefile

## 语言选项

[English](./Readme.md) | [简体中文](./Readme-cn.md)

## 简介

如果我们提供的针对小型工程和中型工程的Makefile无法满足您的工程的要求,或许我们可以将这种工程称为**大型工程**

对于这样的大尺寸、高复杂度的工程,我推荐您使用一些自动化的Makefile构建工具(如CMAKE),或者是与IDE有关的工程管理工具。这些工具更适合于用来解决大型工程的依赖控制,自动化编译构建等工作,可以省去大量人力编写Makefile带来的低效与易错的问题。

CMAKE和一些IDE相关的工程管理工具的使用方法超出了本文的讨论范围,不过我相信您可以在百度,知乎,Github等资源中找到更优质的相关教程。

一般而言,如果您的工程已经超出了本代码仓库提供的小型工程与中型工程的Makefile模板解决方案的讨论范围,那么我不太建议您手写Makefile,特别是在编译效率要求没有那么苛刻(比如内核编译)的情况下。如果您的代码构建需要每个环节都具有最优秀的性能,那么我推荐您邀请专业人士进行Makefile构建,或者参考Linux内核的解决方法。

如果您有对于大型工程Makefile构建的独到间接,或者比较合适的解决方案,还请不吝赐教,提出issue或者pull-request都会是对本代码工程以及其他人莫大的帮助。
4 changes: 4 additions & 0 deletions BigProject/Readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Makefile for BIG Project

## Language

[English](./Readme.md) | [简体中文](./Readme-cn.md)

## Introduction

If the Makefile for SMALL or MEDIUM project are not suitable for your project, then maybe we can call it a BIG project.
Expand Down
80 changes: 80 additions & 0 deletions MediumProject/Readme-cn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# 中型工程的Makefile

## 语言选项

[English](./Readme.md) | [简体中文](./Readme-cn.md)

## 简介

这是一个针对**中型工程**的Makefile模板,我们定义的中型工程是指:

- 可能会有多层嵌套的源代码文件夹
- 一个源代码文件夹下可能有多个源代码子文件夹
- 中间文件应当在其源文件所在目录生成,而不是同一生成到一个目录下(如统一生成到*obj*目录下)
- (大多数情况下)仅有一个目标需要生成

总之,针对这样一个中型大小的工程,我们可以将所有的构建规则都手动添加到顶层Makefile,让它做所有的事情,但是这样对于开发效率,代码增长与后期维护是一个巨大的挑战,所以我们提供这样一个'分布式'的Makefile模板供您参考。

## 如何使用

首先我们推荐您阅读Example文件夹下的范例,并尝试使用各种规则,试着做一些改动,这将帮助您您理解当前的模板。

当您在使用这个模板时,您需要做的事情有:

1.*Template* 目录下的 Makefile 文件复制到您的项目根文件夹
1. 填补标有 `# FILL: ...` 的空白并删除这些注释
1. **注意**: 你需要手动在 `DIRS` 变量中指定所有含有源文件的子文件夹,在 `OBJS` 变量中指定所有当前目录下的中间目标文件
1. 复制 *Template* 下的 *config* 目录到您的项目根文件夹
1. 在文件 *config/make.global* 中指定您需要用到的构建工具
1. 在 Linux/Mac 系统下
1. 由于 `make` 工具一般会在 `PATH` 环境变量中,所以可以删除 `export MAKE := ...` 一行,这个变量存在的意义是在 `PATH` 失效或者是在 Windows 系统中 `make` 被脚本调用时会产生异常的目录查找的情况下,显式指定 `make` 工具路径,弥补一些系统层面的缺陷。
1. Under Windows
1. 填写 `export MAKE := ...` 的空白部分并删除注释
1. 在每一个包含源文件的子文件夹下添加 Makefile, 参照 *Template/src/Makefile* 或者 *Example/.../Makefile* 提供的示例(如果当前目录下没有源文件,但是当前目录的子文件夹中有源文件,则也需要添加一个Makefile到当前目录)

## 情景描述

如果一个工程的目录/源代码组织形式符合如下描述,那么我们称其为**中型工程**:

- 根文件夹: 包含主源文件(有 `main()` 的源文件)
- Makefile: 顶层 Makefile
- 主源文件
- 源文件1
- 目录1
- Makefile
- 源文件2
- 源文件3
- 子目录1
- Makefile
- 源文件4
- 源文件5
- 目录2
- Makefile
- 子目录2
- Makefile
- 源文件6
- 源文件7

## 工作流程

当在根目录执行 `make` 命令时,其首先查看 `TARGET` 指定的文件所依赖的所有文件是否都是最新的,而其依赖的 `ALL_OBJS` 是由规则 `find-all-objs` 来进行查找的。

如果 `TARGET` 任何依赖项不是最新的/还没有生成,则在其源文件所在目录生成对应的中间文件。待所有依赖都更新后,准备进行链接与编译。

在链接时,首先通过 `find-all-objs` 递归查找所有源文件所在目录下的中间文件,并将其统一链接、编译到一个目标文件中。由于在当前环境下每个中间文件都带有路径前缀,所以不同目录下的相同名称的源文件不会产生冲突(例如既存在 *src1/f1.c* 也存在 *src2/f1.c* 是可以的)

## 问题与讨论

1. 为什么每个源文件加都要有一个 Makefile
1. 这样使我们能够在每个源文件所在的目录中维护其自己的中间文件,进一步允许了不同路径下的同名文件的存在。如果将所有中间文件输出到同一个目录下,那么目录1与目录2中的同名文件将生成同名的中间文件到指定目录下,这样会产生覆盖的问题,导致无法正常链接编译,只能额外添加规则或者进行重命名
1. 为什么要手动指定 `DIRS``OBJS` 变量,而不是自动查找
1. 出于这样的考虑: 一些源代码文件并不需要/不应该生成中间文件来参与链接和编译,比如当前目录下模块的单元测试文件 `unit_test.c` ;一些目录并不包含任何源文件,比如只包含文档的目录 *doc* (虽然这些目录也可能包含一些源文件,但其都是说明性代码,并不应该用来参与编译)
1. 如果确实需要自动查找,那么可以通过如下方法实现
1. 在文件 `config/submake.global` 中添加对于 `DIRS``OBJS` 的自动查找规则
1. 将所有子文件夹中的 Makefile 中的手动指定的 `DIRS``OBJS` 变量去除
1. 保持子文件夹中的 Makefile 引用文件 `config/submake.global`
1. 为了突出简洁性与通用性,我们这里不提供自动查找功能(其实在多数中型工程中,手动指定更加稳定且不易出错,反而是自动查找会导致一些隐藏的问题难以发现)
1. 为什么不将所有规则放到 `make.global` 中,而是将一部分放在 `submake.global`
1. 因为子文件夹下的 `all` 规则和 `clean` 规则与根文件夹下有所不同,如果在 `make.global` 中添加这两个规则,会与根文件夹下的 Makefile 冲突,所以这里分成两个文件存放,但是引用时仅需引用 `submake.global` 即可,其中已经引用了 `make.global` 的所有内容
1. 为什么重新构建时,即时所有的依赖文件都是最新的,`TARGET` 仍然会重新编译一遍
1. 这个问题一般是由于 `$(TARGET)` 规则依赖了一些 PHONY 规则,这些规则不产生其名称对应的文件,所以有可能被认为总是过时的,需要重新执行并重新编译。目前来讲我们还没有更好的解决方案,只好容忍这一冗余的存在。不过如果您有更好地解决方案,还望不吝赐教,提出 issue 或者 pull-request 均是对本代码和其他人莫大的帮助。
6 changes: 5 additions & 1 deletion MediumProject/Readme.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Makefile for SMALL Project
# Makefile for MEDIUM Project

## Language

[English](./Readme.md) | [简体中文](./Readme-cn.md)

## Introduction

Expand Down
17 changes: 17 additions & 0 deletions Readme-cn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Makefile 模板

## 语言选项

[English](./Readme.md) | [简体中文](./Readme-cn.md)

## 简介

这个仓库针对不同大小与复杂度的工程,提供了不同的**Makefile模板**,分别对应从小到只包含一个'扁平的'源文件组织结构的小工程,到大到有比较'复杂'的结构的工程。

这些模板并非全都是非常简洁清晰的,甚至其中有一部分模板在工程不断增长后会带来一些难以预料的副作用。但是本仓库提供的是针对**不同尺寸与复杂度的工程**的Makefile模板,所以每个模板必然针对其要解决的问题进行了简化与优化,随之而来的就是无法动态地适应所有情况。当然这也是我们尝试做了一些分类的原因,毕竟针对一些简单的工程,可能只有几个源文件,不需要非常复杂的Makefile,那么提供一个短小精悍,功能足够的模板就可以了;针对一些可能会有所增长,需要自适应但是也需要一些灵活性的中等规模的工程,我们提供了一个比较可行的解决方案;对于更大型,更复杂的工程,我们推荐使用自动化的工具来帮你完成手写Makefile难以完成的任务。

本代码基于MIT协议开源,请尽管使用(在协议允许的范围内)。同时也随时欢迎任何issue和pull-request。

## 证书

[![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=plastic)](https://github.com/TheNetAdmin/Makefile-Templates/blob/master/LICENSE)
4 changes: 4 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Makefile Templates

## Language

[English](./Readme.md) | [简体中文](./Readme-cn.md)

## Introduction

Here are some **Makefile Templates** for different size of projects, from a simple project which has a 'flat' source file structure, to a bigger project which has a 'complex' structure.
Expand Down
47 changes: 47 additions & 0 deletions SmallProject/Readme-cn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 小型工程的 Makefile

## 语言选项

[English](./Readme.md) | [简体中文](./Readme-cn.md)

## 简介

这是一个针对**小型工程**的Makefile模板,我们定义的小型工程是指:

- 只有 **一个** **一层的** 源代码文件夹(即此文件夹下的任何子文件夹中不包含与编译有关的源文件)
- 只有一个目标需要构建

## 如何使用

使用此模板时,将 `Template` 目录下的 Makefile 模板复制到您的工程文件夹下,根据 `Example` 中提供的样例与下述指导来修改 Makefile 的内容,即可完成移植。

## 情景描述

如果一个工程的目录/源代码组织形式符合如下描述,那么我们称其为**小型工程**:

- 根目录: 包含**主源文件**
- bin 目录: 包含目标文件
- obj 目录: 包含所有中间文件
- src: 包含**所有**与编译有关的源文件
- **注意**: src 目录下的子文件夹中不应包含任何与编译有关的源文件,如有,请移动到 src 的根目录下

## 工作流程

在根目录执行 `make`,其生成目标文件依赖于 `OBJ`

`OBJ` 根据 `SRC` 来生成所有的目标文件名,而 `SRC` 是通过搜索 `SRC_PATH` 下所有符合模式 *.c\** 的文件而实现(*.c*, *.cpp*, *.cc* 等文件均会被包括)

如果 `OBJ` 中有任何过时/没有生成的中间文件,会首先生成对应中间文件,然后重新生成目标文件

## 问题与讨论

1. `SRC_PATH` 的子目录是否可以放置编译相关的议决案文件
1. 一般来讲,可以这么做,仅需针对 Makefile 中的 `SRC` 生成方式做少量递归化改动即可
1. 但是我并不建议这么做,这样会隐藏文件名冲突的问题,即如果在不同文件夹下有相同名称的源文件,使用这样一个 Makefile 无法在编译时提示你中间文件重复/覆盖,仅会提示一些与链接有关的问题(如找不到一些函数原型)
1. 如果您的工程比当前问题描述的工程更加复杂,建议您查看**中型工程**或者**大型工程**的 Makfile 模板
1. 为何将所有中间文件放到同一目录?
1. 因为我们针对的是简单的小工程,将所有中间文件放到同一目录方便进行链接与清理
1. 在 Windows 下编译需要注意什么事情
1. 你或许需要显式指定 `make` 工具的路径,如`MAKE := C:/.../make.exe`
1. `TARGET` 应当以 *.exe* 结尾, 如果不这么做,一些情况下 `make` 或者编译器会替你这么做,进一步导致清理时对应的规则失效,这个生成的目标文件无法被正确清理
1. 请不要使用 UNIX 风格的 `find` 功能,如果确实需要使用类似功能,请参考 Windows 下的相关命令,或者参考**中型工程**模板中的递归查找函数 `rwildcard`
10 changes: 8 additions & 2 deletions SmallProject/Readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Makefile for SMALL Project

## Language

[English](./Readme.md) | [简体中文](./Readme-cn.md)

## Introduction

This is the template for **SMALL** Project, which has the features like:
Expand All @@ -8,6 +12,8 @@ This is the template for **SMALL** Project, which has the features like:
- All source files are in the same folder, no sub src dirs
- Only one target to build

## How to

To use this template, copy the template file in `Template` folder to your project folder, and modify it according to comments and the following section of this manual.

## Problem description
Expand All @@ -24,7 +30,7 @@ Assume we have a project with the following folder structure, we call it a **Sma

When execute the command `make`, *make* will first look into the target's dependencis, which are listed in `OBJ`, withc further depend on `SRC`.

The `SRC` is generated by traversing the folder `SRC_FOLDER` and find all the srcfiles ended with *.c\**(which means it will consider the files ended with *.c*, *.cpp*, *.cc*, etc.)
The `SRC` is generated by traversing the folder `SRC_PATH` and find all the srcfiles ended with *.c\**(which means it will consider the files ended with *.c*, *.cpp*, *.cc*, etc.)

After the `SRC` is generated, it will transform into `OBJ`:

Expand All @@ -37,7 +43,7 @@ If any of the `OBJ`'s object is out-dated, it will be re-generated and futher, t

## FAQs and Discussions

1. Shall I put src files in sub-dirs of `SRC_DIR`?
1. Shall I put src files in sub-dirs of `SRC_PATH`?
1. Basically, YES. You could put some srcs in such sub-dirs, and add some new rules to the Makefile.
1. BUT, I do NOT recomment you to do this. Consider we have two srcs, *src/sub1/src1.c*, *src/sub2/src1.c*. They would not conflict when we write the code. But remember ALL the objects will be output tot `OBJ_PATH`, when compiling, they will conflict, and the linker will be confused.
1. So, what if I really need to do so? Consider using the Template **MediumProject** we provided.
Expand Down

0 comments on commit 4ac7ccb

Please sign in to comment.