無需手寫任何代碼,直接快速編譯源代碼

最近給xmake增加了一個新特性,對於一份工程源碼,可以不用編寫makefile,也不用編寫各種make相關的工程描述文件(例如:xmake.lua,makefile.am, cmakelist.txt等)

xmake就可以直接編譯他們,這是如何做到的呢,簡單來說下實現原理:

  1. 首先掃描當前目錄下,xmake所以支持的所有源代碼文件

  2. 分析代碼,檢測哪些代碼擁有main入口函數

  3. 所有沒有main入口的代碼編譯成靜態庫

  4. 帶有main入口的代碼,編譯成可執行程序,同時鏈接其他靜態庫程序

這種代碼掃描和智能編譯,非常簡單,目前xmake還不支持多級目錄掃描,只對單級目錄的代碼進行掃描編譯。。

開源代碼的移植和編譯

雖然這種方式,並不是非常智能,限制也不少,但是對於想臨時寫些代碼進行編譯運行,或者臨時想交叉編譯一些簡單的開源庫代碼

這種方式已經足夠使用了,下面看下一個實際的例子:

我下載了一份zlib-1.2.10的源碼,想要編譯它,只需要進入zlib的源碼目錄執行:

$ cd zlib-1.2.10n$ xmaken

就行了,輸出結果如下:

xmake.lua not found, scanning files ..ntarget(zlib-1.2): staticn [+]: ./adler32.cn [+]: ./compress.cn [+]: ./crc32.cn [+]: ./deflate.cn [+]: ./gzclose.cn [+]: ./gzlib.cn [+]: ./gzread.cn [+]: ./gzwrite.cn [+]: ./infback.cn [+]: ./inffast.cn [+]: ./inflate.cn [+]: ./inftrees.cn [+]: ./trees.cn [+]: ./uncompr.cn [+]: ./zutil.cnxmake.lua generated, scan ok!??nchecking for the architecture ... x86_64nchecking for the Xcode SDK version for macosx ... 10.12nchecking for the target minimal version ... 10.12nchecking for the c compiler (cc) ... xcrun -sdk macosx clangnchecking for the c++ compiler (cxx) ... xcrun -sdk macosx clangnchecking for the objc compiler (mm) ... xcrun -sdk macosx clangnchecking for the objc++ compiler (mxx) ... xcrun -sdk macosx clang++nchecking for the swift compiler (sc) ... xcrun -sdk macosx swiftcnchecking for the assember (as) ... xcrun -sdk macosx clangnchecking for the linker (ld) ... xcrun -sdk macosx clang++nchecking for the static library archiver (ar) ... xcrun -sdk macosx arnchecking for the static library extractor (ex) ... xcrun -sdk macosx arnchecking for the shared library linker (sh) ... xcrun -sdk macosx clang++nchecking for the debugger (dd) ... xcrun -sdk macosx lldbnchecking for the golang compiler (go) ... gonconfiguren{n ex = "xcrun -sdk macosx ar"n, sh = "xcrun -sdk macosx clang++"n, host = "macosx"n, ar = "xcrun -sdk macosx ar"n, buildir = "build"n, as = "xcrun -sdk macosx clang"n, plat = "macosx"n, xcode_dir = "/Applications/Xcode.app"n, arch = "x86_64"n, mxx = "xcrun -sdk macosx clang++"n, go = "go"n, target_minver = "10.12"n, ccache = "ccache"n, mode = "release"n, clean = truen, cxx = "xcrun -sdk macosx clang"n, cc = "xcrun -sdk macosx clang"n, dd = "xcrun -sdk macosx lldb"n, kind = "static"n, ld = "xcrun -sdk macosx clang++"n, xcode_sdkver = "10.12"n, sc = "xcrun -sdk macosx swiftc"n, mm = "xcrun -sdk macosx clang"n}nconfigure ok!nclean ok!n[00%]: ccache compiling.release ./adler32.cn[06%]: ccache compiling.release ./compress.cn[13%]: ccache compiling.release ./crc32.cn[20%]: ccache compiling.release ./deflate.cn[26%]: ccache compiling.release ./gzclose.cn[33%]: ccache compiling.release ./gzlib.cn[40%]: ccache compiling.release ./gzread.cn[46%]: ccache compiling.release ./gzwrite.cn[53%]: ccache compiling.release ./infback.cn[60%]: ccache compiling.release ./inffast.cn[66%]: ccache compiling.release ./inflate.cn[73%]: ccache compiling.release ./inftrees.cn[80%]: ccache compiling.release ./trees.cn[86%]: ccache compiling.release ./uncompr.cn[93%]: ccache compiling.release ./zutil.cn[100%]: archiving.release libzlib-1.2.anbuild ok!??n

通過輸出結果,可以看到,xmake會去檢測掃描當前目錄下的所有.c代碼,發現沒有main入口,應該是靜態庫程序,因此執行xmake後,就直接編譯成靜態庫libzlib-1.2.a了

連xmake.lua都沒有編寫,其實xmake在掃描完成後,會去自動在當前目錄下生成一份xmake.lua,下次編譯就不需要重新掃描檢測了。

自動生成的xmake.lua內容如下:

-- define targetntarget("zlib-1.2")nn -- set kindn set_kind("static")nn -- add filesn add_files("./adler32.c")n add_files("./compress.c")n add_files("./crc32.c")n add_files("./deflate.c")n add_files("./gzclose.c")n add_files("./gzlib.c")n add_files("./gzread.c")n add_files("./gzwrite.c")n add_files("./infback.c")n add_files("./inffast.c")n add_files("./inflate.c")n add_files("./inftrees.c")n add_files("./trees.c")n add_files("./uncompr.c")n add_files("./zutil.c")n

也許你會說,像這種開源庫,直接configure; make不就好了嗎,他們自己也有提供makefile來直接編譯的,的確是這樣,我這裡只是舉個例子而已。。

當然,很多開源庫在交叉編譯的時候,通過自帶的configure,處理起來還是很繁瑣的,用xmake進行交叉編譯會更方便些。。

即時地代碼編寫和編譯運行

xmake的這個掃描代碼編譯特性,主要的目的:還是為了讓我們在臨時想寫些測試代碼的時候,不用考慮太多東西,直接上手敲代碼,然後快速執行xmake run 來調試驗證結果。。

例如:

我想寫了個簡單的main.c的測試程序,列印hello world!,如果要寫makefile或者直接通過gcc命令來,就很繁瑣了,你需要:

gcc ./main.c -o demon./demon

最快速的方式,也需要執行兩行命令,而如果用xmake,只需要執行:

xmake runn

就行了,它會自動檢測到代碼後,自動生成對應的xmake.lua,自動編譯,自動運行,然後輸出:

hello world!n

如果你有十幾個代碼文件,用手敲gcc的方式,或者寫makefile的方式,這個差距就更明顯了,用xmake還是只需要一行命令:

xmake runn

多語言支持

這種代碼檢測和即時編譯,是支持多語言的,不僅支持c/c++,還支持objc/swift,後期還會支持golang(正在開發中)

例如我下載了一份fmdb的ios開源框架代碼:

.n├── FMDB.hn├── FMDatabase.hn├── FMDatabase.mn├── FMDatabaseAdditions.hn├── FMDatabaseAdditions.mn├── FMDatabasePool.hn├── FMDatabasePool.mn├── FMDatabaseQueue.hn├── FMDatabaseQueue.mn├── FMResultSet.hn└── FMResultSet.mn

想要把它編譯成ios的靜態庫,但是又不想寫xmake.lua,或者makefile,那麼只需要使用xmake的這個新特性,直接執行:

$ xmake f -p iphoneos; xmaken

就行了,輸出結果如下:

xmake.lua not found, scanning files ..ntarget(FMDB): staticn [+]: ./FMDatabase.mn [+]: ./FMDatabaseAdditions.mn [+]: ./FMDatabasePool.mn [+]: ./FMDatabaseQueue.mn [+]: ./FMResultSet.mnxmake.lua generated, scan ok!??nchecking for the architecture ... armv7nchecking for the Xcode SDK version for iphoneos ... 10.1nchecking for the target minimal version ... 10.1nchecking for the c compiler (cc) ... xcrun -sdk iphoneos clangnchecking for the c++ compiler (cxx) ... xcrun -sdk iphoneos clangnchecking for the objc compiler (mm) ... xcrun -sdk iphoneos clangnchecking for the objc++ compiler (mxx) ... xcrun -sdk iphoneos clang++nchecking for the assember (as) ... gas-preprocessor.pl xcrun -sdk iphoneos clangnchecking for the linker (ld) ... xcrun -sdk iphoneos clang++nchecking for the static library archiver (ar) ... xcrun -sdk iphoneos arnchecking for the static library extractor (ex) ... xcrun -sdk iphoneos arnchecking for the shared library linker (sh) ... xcrun -sdk iphoneos clang++nchecking for the swift compiler (sc) ... xcrun -sdk iphoneos swiftcnconfiguren{n ex = "xcrun -sdk iphoneos ar"n, ccache = "ccache"n, host = "macosx"n, ar = "xcrun -sdk iphoneos ar"n, buildir = "build"n, as = "/usr/local/share/xmake/tools/utils/gas-preprocessor.pl xcrun -sdk iphoneos clang"n, arch = "armv7"n, mxx = "xcrun -sdk iphoneos clang++"n, cxx = "xcrun -sdk iphoneos clang"n, target_minver = "10.1"n, xcode_dir = "/Applications/Xcode.app"n, clean = truen, sh = "xcrun -sdk iphoneos clang++"n, cc = "xcrun -sdk iphoneos clang"n, ld = "xcrun -sdk iphoneos clang++"n, mode = "release"n, kind = "static"n, plat = "iphoneos"n, xcode_sdkver = "10.1"n, sc = "xcrun -sdk iphoneos swiftc"n, mm = "xcrun -sdk iphoneos clang"n}nconfigure ok!nclean ok!n[00%]: ccache compiling.release ./FMDatabase.mn[20%]: ccache compiling.release ./FMDatabaseAdditions.mn[40%]: ccache compiling.release ./FMDatabasePool.mn[60%]: ccache compiling.release ./FMDatabaseQueue.mn[80%]: ccache compiling.release ./FMResultSet.mn[100%]: archiving.release libFMDB.anbuild ok!??n

同時編譯多個可執行文件

輸出結果的開頭部分,就是對代碼的分析結果,雖然目前只支持單級目錄結構的代碼掃描,但是還是可以同時支持檢測和編譯多個可執行文件的

我們以libjpeg的開源庫為例:

我們進入jpeg-6b目錄後,執行:

$ xmaken

輸出如下:

xmake.lua not found, scanning files ..ntarget(jpeg-6b): staticn [+]: ./cdjpeg.cn [+]: ./example.cn [+]: ./jcapimin.cn [+]: ./jcapistd.cn [+]: ./jccoefct.cn [+]: ./jccolor.cn [+]: ./jcdctmgr.cn [+]: ./jchuff.cn [+]: ./jcinit.cn [+]: ./jcmainct.cn [+]: ./jcmarker.cn [+]: ./jcmaster.cn [+]: ./jcomapi.cn [+]: ./jcparam.cn [+]: ./jcphuff.cn [+]: ./jcprepct.cn [+]: ./jcsample.cn [+]: ./jctrans.cn [+]: ./jdapimin.cn [+]: ./jdapistd.cn [+]: ./jdatadst.cn [+]: ./jdatasrc.cn [+]: ./jdcoefct.cn [+]: ./jdcolor.cn [+]: ./jddctmgr.cn [+]: ./jdhuff.cn [+]: ./jdinput.cn [+]: ./jdmainct.cn [+]: ./jdmarker.cn [+]: ./jdmaster.cn [+]: ./jdmerge.cn [+]: ./jdphuff.cn [+]: ./jdpostct.cn [+]: ./jdsample.cn [+]: ./jdtrans.cn [+]: ./jerror.cn [+]: ./jfdctflt.cn [+]: ./jfdctfst.cn [+]: ./jfdctint.cn [+]: ./jidctflt.cn [+]: ./jidctfst.cn [+]: ./jidctint.cn [+]: ./jidctred.cn [+]: ./jmemansi.cn [+]: ./jmemmgr.cn [+]: ./jmemname.cn [+]: ./jmemnobs.cn [+]: ./jquant1.cn [+]: ./jquant2.cn [+]: ./jutils.cn [+]: ./rdbmp.cn [+]: ./rdcolmap.cn [+]: ./rdgif.cn [+]: ./rdppm.cn [+]: ./rdrle.cn [+]: ./rdswitch.cn [+]: ./rdtarga.cn [+]: ./transupp.cn [+]: ./wrbmp.cn [+]: ./wrgif.cn [+]: ./wrppm.cn [+]: ./wrrle.cn [+]: ./wrtarga.cntarget(ansi2knr): binaryn [+]: ./ansi2knr.cntarget(cjpeg): binaryn [+]: ./cjpeg.cntarget(ckconfig): binaryn [+]: ./ckconfig.cntarget(djpeg): binaryn [+]: ./djpeg.cntarget(jpegtran): binaryn [+]: ./jpegtran.cntarget(rdjpgcom): binaryn [+]: ./rdjpgcom.cntarget(wrjpgcom): binaryn [+]: ./wrjpgcom.cnxmake.lua generated, scan ok!??nchecking for the architecture ... x86_64nchecking for the Xcode SDK version for macosx ... 10.12nchecking for the target minimal version ... 10.12nchecking for the c compiler (cc) ... xcrun -sdk macosx clangnchecking for the c++ compiler (cxx) ... xcrun -sdk macosx clangnchecking for the objc compiler (mm) ... xcrun -sdk macosx clangnchecking for the objc++ compiler (mxx) ... xcrun -sdk macosx clang++nchecking for the swift compiler (sc) ... xcrun -sdk macosx swiftcnchecking for the assember (as) ... xcrun -sdk macosx clangnchecking for the linker (ld) ... xcrun -sdk macosx clang++nchecking for the static library archiver (ar) ... xcrun -sdk macosx arnchecking for the static library extractor (ex) ... xcrun -sdk macosx arnchecking for the shared library linker (sh) ... xcrun -sdk macosx clang++nchecking for the debugger (dd) ... xcrun -sdk macosx lldbnchecking for the golang compiler (go) ... gonconfiguren{n ex = "xcrun -sdk macosx ar"n, sh = "xcrun -sdk macosx clang++"n, host = "macosx"n, ar = "xcrun -sdk macosx ar"n, buildir = "build"n, as = "xcrun -sdk macosx clang"n, plat = "macosx"n, xcode_dir = "/Applications/Xcode.app"n, arch = "x86_64"n, mxx = "xcrun -sdk macosx clang++"n, go = "go"n, target_minver = "10.12"n, ccache = "ccache"n, mode = "release"n, clean = truen, cxx = "xcrun -sdk macosx clang"n, cc = "xcrun -sdk macosx clang"n, dd = "xcrun -sdk macosx lldb"n, kind = "static"n, ld = "xcrun -sdk macosx clang++"n, xcode_sdkver = "10.12"n, sc = "xcrun -sdk macosx swiftc"n, mm = "xcrun -sdk macosx clang"n}nconfigure ok!nclean ok!n[00%]: ccache compiling.release ./cdjpeg.cn[00%]: ccache compiling.release ./example.cn[00%]: ccache compiling.release ./jcapimin.cn[00%]: ccache compiling.release ./jcapistd.cn[00%]: ccache compiling.release ./jccoefct.cn[00%]: ccache compiling.release ./jccolor.cn[01%]: ccache compiling.release ./jcdctmgr.cn[01%]: ccache compiling.release ./jchuff.cn[01%]: ccache compiling.release ./jcinit.cn[01%]: ccache compiling.release ./jcmainct.cn[01%]: ccache compiling.release ./jcmarker.cn[02%]: ccache compiling.release ./jcmaster.cn[02%]: ccache compiling.release ./jcomapi.cn[02%]: ccache compiling.release ./jcparam.cn[02%]: ccache compiling.release ./jcphuff.cn[02%]: ccache compiling.release ./jcprepct.cn[03%]: ccache compiling.release ./jcsample.cn[03%]: ccache compiling.release ./jctrans.cn[03%]: ccache compiling.release ./jdapimin.cn[03%]: ccache compiling.release ./jdapistd.cn[03%]: ccache compiling.release ./jdatadst.cn[04%]: ccache compiling.release ./jdatasrc.cn[04%]: ccache compiling.release ./jdcoefct.cn[04%]: ccache compiling.release ./jdcolor.cn[04%]: ccache compiling.release ./jddctmgr.cn[04%]: ccache compiling.release ./jdhuff.cn[05%]: ccache compiling.release ./jdinput.cn[05%]: ccache compiling.release ./jdmainct.cn[05%]: ccache compiling.release ./jdmarker.cn[05%]: ccache compiling.release ./jdmaster.cn[05%]: ccache compiling.release ./jdmerge.cn[06%]: ccache compiling.release ./jdphuff.cn[06%]: ccache compiling.release ./jdpostct.cn[06%]: ccache compiling.release ./jdsample.cn[06%]: ccache compiling.release ./jdtrans.cn[06%]: ccache compiling.release ./jerror.cn[07%]: ccache compiling.release ./jfdctflt.cn[07%]: ccache compiling.release ./jfdctfst.cn[07%]: ccache compiling.release ./jfdctint.cn[07%]: ccache compiling.release ./jidctflt.cn[07%]: ccache compiling.release ./jidctfst.cn[08%]: ccache compiling.release ./jidctint.cn[08%]: ccache compiling.release ./jidctred.cn[08%]: ccache compiling.release ./jmemansi.cn[08%]: ccache compiling.release ./jmemmgr.cn[08%]: ccache compiling.release ./jmemname.cn[09%]: ccache compiling.release ./jmemnobs.cn[09%]: ccache compiling.release ./jquant1.cn[09%]: ccache compiling.release ./jquant2.cn[09%]: ccache compiling.release ./jutils.cn[09%]: ccache compiling.release ./rdbmp.cn[10%]: ccache compiling.release ./rdcolmap.cn[10%]: ccache compiling.release ./rdgif.cn[10%]: ccache compiling.release ./rdppm.cn[10%]: ccache compiling.release ./rdrle.cn[10%]: ccache compiling.release ./rdswitch.cn[11%]: ccache compiling.release ./rdtarga.cn[11%]: ccache compiling.release ./transupp.cn[11%]: ccache compiling.release ./wrbmp.cn[11%]: ccache compiling.release ./wrgif.cn[11%]: ccache compiling.release ./wrppm.cn[12%]: ccache compiling.release ./wrrle.cn[12%]: ccache compiling.release ./wrtarga.cn[12%]: archiving.release libjpeg-6b.an[12%]: ccache compiling.release ./wrjpgcom.cn[25%]: linking.release wrjpgcomn[25%]: ccache compiling.release ./ansi2knr.cn[37%]: linking.release ansi2knrn[37%]: ccache compiling.release ./jpegtran.cn[50%]: linking.release jpegtrann[50%]: ccache compiling.release ./djpeg.cn[62%]: linking.release djpegn[62%]: ccache compiling.release ./ckconfig.cn[75%]: linking.release ckconfign[75%]: ccache compiling.release ./rdjpgcom.cn[87%]: linking.release rdjpgcomn[87%]: ccache compiling.release ./cjpeg.cn[100%]: linking.release cjpegnbuild ok!??n

可以看到,處理靜態庫,xmake還分析出了很多可執行的測試程序,剩下的代碼統一編譯成一個 libjpeg.a 的靜態庫,供哪些測試程序鏈接使用。。

target(ansi2knr): binaryn [+]: ./ansi2knr.cntarget(cjpeg): binaryn [+]: ./cjpeg.cntarget(ckconfig): binaryn [+]: ./ckconfig.cntarget(djpeg): binaryn [+]: ./djpeg.cntarget(jpegtran): binaryn [+]: ./jpegtran.cntarget(rdjpgcom): binaryn [+]: ./rdjpgcom.cntarget(wrjpgcom): binaryn [+]: ./wrjpgcom.cn

遇到的一些問題和限制

當前xmake的這種自動分析檢測還不是非常智能,對於:

  1. 需要特殊的編譯選項

  2. 需要依賴其他目錄的頭文件搜索

  3. 需要分條件編譯不同源文件

  4. 同目錄需要生成多個靜態庫

  5. 需要多級目錄支持的源碼庫

以上這些情況,xmake暫時還沒發自動化的智能處理,其中限制1,2還是可以解決的,通過半手動的方式,例如:

$ xmake f --cxflags="" --ldflags="" --includedirs="" --linkdirs=""; xmaken

在自動檢測編譯的時候,手動配置這個源碼工程需要的特殊編譯選項,就可以直接通過編譯了

而限制3,暫時只能通過刪源代碼來解決了,就像剛才編譯jpeg的代碼,其實它的目錄下面同時存在了:

jmemdos.cnjmemmac.cnjmemansi.cn

其中兩個是沒法編譯過的,需要刪掉後才行。。

個人主頁:TBOOX開源工程

原文出處:xmake新增智能代碼掃描編譯模式

推薦閱讀:

macOS Sierra10.12.6下安裝OpenCV3.3.0
vs2017怎麼用內置CMAKE編譯opencv??
解決 Windows 下 Python 安裝 Dlib 的問題:Cmake 找不到 boost

TAG:make | Makefile | CMake |