Giter VIP home page Giter VIP logo

emake's Introduction

Preface

GNU Make 太麻烦?Makefile 写起来太臃肿?头文件依赖生成搞不定?多核同时编译太麻烦?Emake 帮你解决这些问题:

  • 使用简单:设定源文件,设定编译参数和输出目标就行了,emake为你打点好一切。
  • 依赖分析:快速分析源代码所依赖的头文件,决定是否需要重新编译。
  • 输出模式:可执行、静态库(.a)、动态库(.so/.dll)。
  • 多核编译:轻松实现并行编译,加速项目构建。
  • 精简紧凑:只有唯一的一个 emake.py 文件。
  • 干净利索:无需导出 Makefile/.sln 等中间文件,构建一步到位。
  • 交叉编译:构建 iOS 项目 ,安卓项目,等等。
  • 语言支持 C / C++ / ObjC / ObjC++ / ASM
  • 工具支持 gcc / mingw / clang
  • 运行系统 Windows / Linux / Mac OS X / FreeBSD
  • 信息导出:项目文件列表,目标文件,以及 compile_commands.json 等。
  • 方便的交叉编译,轻松构建 Android NDK / iOS / asm.js 项目
  • 你见过最简单的构建系统,比 Gnu Make / CMake 都简单很多

只有两三个源代码,那 makefile 随便写,文件一多,搞依赖都可以搞死人。emake 就是简单中的简单,不但比 GNU Make 简单,还要比 cmake 简单很多。

应为 CMake 和 GNU Make 都是命令式构建工具,而 emake 是定义式构建工具,命令式当然可以处理各种复杂情况,本身就是一门编程语言,强大却失之复杂,而定义式类似 IDE 那样,设定文件,编译参数链接参数,就能开始工作了,虽然做不到命令式那么灵活,但能满足大多数中小型项目开发,个人实验项目的日常开发。

Emake 是为快速开发而生的,通过牺牲了部分灵活性,却换来了极大的便利性,最初版本在 2009年发布,多年间团队在不同操作系统下用它构建过:服务端项目、客户端项目、iOS项目、安卓项目 和 Flash项目,这些项目都稳健的跑在生产环境中,为海量用户提供服务。

多年的开发中,emake 提高了各种大小项目的开发效率,自身也随着时间增加不断被完善和稳定。

Install

Linux / Mac OS X:

wget http://skywind3000.github.io/emake/emake.py
sudo python2 emake.py -i

运行上面两条指令,十秒内完成安装。emake 会拷贝自己到 /usr/local/bin 下面,后面直接使用 emake 指令操作。

Windows:

下载 emake.py,放到你的 mingw 根目录下(便于 emake 定位 gcc),并且添加到 PATH 环境变量,同级目录新建立一个 emake.cmd 文件,内容如下:

@echo off
d:\dev\python27\python.exe d:\dev\mingw\emake.py %*

修改一下对应路径即可,建立这个 emake.cmd 的批处理文件是为了方便每次敲 emake 就可以工作,避免敲 "python emake.py" 一长串。

Tutorial

假设你有三个文件:foo.c, bar.c, main.c 共同编译成名字为 main(.exe) 的可执行文件,我们创建 “main.mak” 文件:

; 指明目标格式:exe, lib, dll 三选一
mode: exe

; 加入源文件
src: foo.c
src: bar.c
src: main.c

是不是比 makefile, cmake 之类的步骤简单多了?编译项目:

emake main.mak

好了,工程顺利编译成功,每次任何一个文件发生变动,相关对其依赖的源文件都会重新编译,而无依赖的代码则不需要再次编译。

增加编译选项

如果需要增加编译选项的话:

; 指明目标格式:exe, lib, dll 三选一
mode: exe

; 编译选项
flag: -Wall, -O3, -g

; 加入源文件
src: foo.c
src: bar.c
src: main.c

如果项目中使用了数学库 libm.a的话:

link: m

如果还是用了 libstdc++.a 的话:

link: m, stdc++

或者:

link: m
link: stdc++

link 可以直接写 .a 库的文件名:

link: ./lib/libmylib.a

如果需要添加额外的 include 目录 和 lib 目录的话:

inc: /usr/local/opt/jdk/include
lib: /usr/local/opt/jdk/lib

还可以手动指定输出的文件名:

out: main

手动指定临时文件夹,避免临时 .o 文件污染当前目录的话:

int: objs

这样所有的临时文件就会跑到 objs 目录下面了,想要清理的话,删除 objs目录即可。

完整例子

; 指明目标格式:exe, lib, dll 三选一
mode: exe

; 编译选项
flag: -Wall, -O3, -g

; 设定链接
link: m, pthread, stdc++

; 额外头文件路径
inc: /usr/local/opt/jdk/include
inc: /usr/local/opt/jdk/include/linux

; 额外库文件路径
lib: /usr/local/opt/jdk/lib

; 加入源文件
src: foo.c
src: bar.c
src: main.c

Document

emake 的工程文件里面支持下面几种设置:

src

用于声明项目里面的源文件,格式:

src: file1
src: file2
...
src: filen

或者:

src: file1, file2, file3
src: file4, file5, file6

inc

声明项目中的 include 文件夹,相当于 gcc 的 -I 命令:

inc: dir1
inc: dir2

或者:

inc: dir1, dir2

和 src 一样可以使用逗号分隔。

lib

设置库文件目录,格式同上

link

添加需要链接的库,相当于 gcc 的 -l 指令:

link: m, pthread, stdc++

或者:

link: m
link: pthread
link: stdc++

同时支持单行和多行模式,编译 C++ 项目别忘记链接 stdc++。

mode

目标文件的输出格式:

mode: [exe|lib|dll|win]
  • exe: 生成可执行文件
  • lib: 生成静态链接库
  • dll: 生成动态链接库
  • win: windows下特有,生成无 console窗口的 windows程序。

out

指定目标文件的文件名:

out: target_file_name

int

指定中间临时文件目录,一般设置为:

int: objs

或者:

int: objs/$(target)

flag

指定编译参数,会被直接传递给 gcc.

flag: -Wall, -g, -pg

诸如此类

Events

根据条件运行不同 shell 命令:

# 加载前
preload: echo "preload"

# 编译前
prebuild: echo "prebuild"

# 链接前
prelink: echo "prelink"

# 编译后
postbuild: echo "postbuild"

其中 preloadprebuild 之间的区别是,preload 每次都会运行,并且是在解析项目文件和分析依赖之前运行,而 prebuild 是在解析项目文件分析依赖之后运行,如果二进制没更新,prebuild 就不会被调用,而 preload 每次都无条件被执行。

比如某个源代码是使用其他工具生成的,放到 prebuild 时,应为处于依赖分析之后,初次构建尚未触发生成代码前面依赖分析就会报找不到文件了,但 preload 在依赖分析之前运行。

Settings

Emake 可以指定一个 ini 文件来进行全局配置:

原来是:

emake <parameters>

手动指定配置文件名:

emake --ini=xxx.ini <parameters> 

如果不指明的话,会首先在当前文件夹寻找 emake.ini 文件,同时 Linux 下面的话,还会相继在下面三个位置:

/etc/emake.ini
/usr/local/etc/emake.ini
~/.config/emake.ini

两外一种指定配置的方式是 --cfg=name 方式:

emake --cfg=mingw64 <parameters>

这样它会去试图加载 ~/.config/emake/{name}.ini ,方便你集中管理不同的全局配置文件。

进行寻找。该配置文件确定了一些编译的默认配置,在该配置文件中,可以:

  • 更改默认编译器的可执行文件名
  • 更改默认连接器的可执行文件名
  • 设定编译条件
  • 设定默认编译的参数:include / lib 等文件夹等
  • 设定编译器启动的一些环境变量
  • 设定多核编译时的 cpu 数量。
  • 预先设定一些 section,工程文件可以 import 特定的 section。

由上面这些设定,emake 可以灵活的调用各种工具链,方便的进行项目构建和交叉编译。比如我在 Windows 下面的 emake.ini 部分内容:

[default]
flag=-Wall, -I$(inihome)/../mylibs
link=stdc++, winmm, wsock32, opengl32, gdi32, glu32, ws2_32, user32

include=d:/dev/local/include
lib=d:/dev/local/lib

cpu=6

[ffmpeg]
include=d:/dev/local/opt/ffmpeg/include
lib=d:/dev/local/opt/ffmpeg/lib
link=avcodec, avdevice, avfilter, avformat, avutil, postproc, swscale


[qt]
include=D:/Dev/Qt/sdk/4.8.3-mingw/include;D:/Dev/Qt/sdk/4.8.3-mingw/include/QtGui
lib=D:/Dev/Qt/sdk/4.8.3-mingw/lib
link=stdc++, ole32, gdi32, wsock32, opengl32, gdi32, glu32, ws2_32, uuid, oleaut32, winmm, imm32, winspool, QtCore4, QtGui4, QtGuid4

[qt45]
include=D:/Dev/Qt/4.5.0-mingw-static/include;D:/Dev/Qt/4.5.0-mingw-static/include/QtGui
lib=D:/Dev/Qt/4.5.0-mingw-static/lib
link=stdc++, ole32, gdi32, wsock32, opengl32, gdi32, glu32, ws2_32, uuid, oleaut32, winmm, imm32, winspool, QtCore, QtGui

默认区(default)作用于每一个工程文件,其中 cpu字段只能出现在默认区,它规定了编译时最多使用多少个核进行编译,其他区的话,需要在工程里使用 import 来导入:

import: qt, ffmpeg

那么在你的工程里,上面 qt 和 ffmpeg 的相关配置就会被导入了。

Cross Compilation

交叉编译的话,需要单独一个 ini 文件来规定工具链,比如我的 android交叉编译配置:

[default]
flag=-Wall
home=bin
gcc=arm-linux-androideabi-gcc
ar=arm-linux-androideabi-ar
as=arm-linux-androideabi-as
name=android,posix,arm
cpu=4

其中 home 规定了 ndk 工具链 gcc 环境所在的可执行路径,可以是绝对路径,或者是相对于 ini 配置文件的相对路径,后面同时定义了:gcc, ar, as 三个必须的可执行文件名,使用的时候:

emake --ini=d://android-toolchain/android-9/emake.ini xxx

或者放到 ~/.config/emake/android-9.ini 里面,用:

emake --cfg=android-9 xxx

指定使用它,在 default 区中定义了很多 name ,这些 name 可以用来做工程文件的条件判断,比如:

android/flag: -mfloat-abi=softfp
posix/link: pthread
win32/link: winmm, wsock32, ws2_32

不同的 ini 文件中定义的 name 不同,在工程文件中会判断是否定义过某个 name ,定义过的话,执行后面的话,如此在同一个工程文件中,可以针对不同平台定义源文件,设置编译参数。

Rapid Development

不管时 GNU Make 还是 cmake,亦或时其他构建系统,都需要你写一个专门的工程文件来描述该工程。对于大项目很正常,但是对于中小项目,特别时一些测试类项目,这真的太麻烦了。

Emake 可以不用工程文件,而将工程配置信息嵌入到源代码的注释中:

#include <stdio.h>
#include <stddef.h>
#include "foobar.h"


//! mode: exe
//! src: foo.cpp, bar.cpp, utils.cpp
int main(void)
{
	printf("Hello, World !!\n");
	foo();
	bar();
	return 0;
}

这样在你的源文件里面增添两行以后,即可使用:

emake main.cpp

来进行编译,emake 会自动提取 //! 开头的注释,解析为 emake的项目描述信息,上面的配置描述了该项目依赖的文件(除了 main.cpp自己外),以及项目模式为生成可执行文件。

这样写起来,比所有构建系统都简单很多。

输出信息

列出项目最终输出文件,比如 xxx.so 之类:

emake -o hello.mak

列出项目所包含的源文件:

emake -list hello.mak

列出编译参数:

emake -cflags hello.mak

列出依赖:

emake -depends hello.mak

输出 compile_commands.json 内容:

emake -commands hello.mak

还有更多信息,具体见:emake -h 说明。

Credits

本项目旧地址:

https://code.google.com/archive/p/easymake/

emake's People

Contributors

alvisisme avatar redpower1998 avatar skywind3000 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emake's Issues

建议在homebrew发布

macos10.15不能修改系统文件了,并且也不想用sudo安装,能不能发布一个homebrew的版本

Python的版本问题

从知乎上过来,请问是否支持python 3?不太想单独为此搞一个python版本

链接参数可否设置

如何添加链接参数,比如,我希望生成map, 需要田间 -wl -Map这个链接 选项,不知道该工具可否实现,谢谢?

c文件依赖的头文件搜索问题

你好,我发现你这边的设计可能存在缺陷,比如:当我的编译选项中添加了头文件引用的目录inc: dir
1,dir2。 当我改了里面的头文件的内容应该是不支持 增量编译的,无法触发 依赖这些头文件的。
因为我分析了你的代码,貌似只支持 搜索到与c文件同一目录下的头文件 依赖关系

怎样实现条件编译?

比如那些 -DXXXXX 的条件,在CMake以及别的很多make中,可以通过这样的条件选项使用不同的头文件啊源码文件啊以及不同的库和选项。从emake的readme看,和这种比较类似的是name? 那么这个怎么使用呢?在不写ini的情况下。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.