# Makefile Note #### [`=`, `:=`, `?=`, `+=` diff ](http://dannysun-unknown.blogspot.com/2015/03/makefile.html) #### patsubst ``` objects = file1.o file2.o file3.o sources = $(patsubst %.o,%.c,$(objects)) ``` >sources= file1.c file2.c file3.c 從$(objects)尋找%.o替換%.c the patsubst function is specific to Makefile and is part of the GNU Make utility #### cygwin hosts chatgpt ``` Cygwin hosts 通常是指在 Windows 上運行 Cygwin 的系統。Cygwin 是一個為 Windows 提供的 POSIX 相容層,允許用戶在 Windows 環境中執行像 Linux/Unix 這樣的指令和應用程式。 ``` #### `ifeq` and `fliter` GNU Make utility ``` ifeq (,$(filter $(UNAME),Linux FreeBSD NetBSD Darwin CYGWIN MSYS2)) ``` 這段代碼會在沒找到這些時執行,報錯。 #### Operating System Wiki ``` NetBSD是一份自由、安全的具有高度可客製化性的類Unix作業系統,適於多種平台,從64位元AMD Athlon伺服器和桌面系統到手持裝置和嵌入式裝置。它設計簡潔,代碼規範,擁有眾多先進特性,使得它在業界和學術界廣受好評,使用者可以通過完整的原始碼獲得支援。 FreeBSD是FreeBSD專案的發展成果,是開放原始碼的類Unix作業系統,基於BSD Unix的原始碼衍生發展而來。 Cygwin是許多自由軟體的集合,最初由Cygnus Solutions開發,用於各種版本的Microsoft Windows上,執行類UNIX系統。Cygwin的主要目的是通過重新編譯,將POSIX系統上的軟體移植到Windows上。 MSYS2 is software distribution and a building platform for Windows. It provides a Unix-like environment, a command-line interface and a software repository making it easier to install, use, build and port software on Windows. That means Bash, Autotools, Make, Git, GCC, GDB..., all easily installable through Pacman, a fully-featured package manager. It is an independent rewrite of MSys, based on modern Cygwin (POSIX compatibility layer) and MinGW-w64 with the aim of better interoperability with native Windows software. ``` #### MAKECMDGOALS makefile的預設變量 ``` make clean all ``` >MAKECMDGOALS= clean all #### 問題 ``` MAKEFLAGS += -l -j 8 -rR --no-print-directory ifneq ($(findstring clean,$(MAKECMDGOALS)),) MAKEFLAGS += -j 1 endif ``` 這會導致`MAKEFLAGS = -j 8 ... -j 1`,可以推論MAKEFLAGS在遇到option重複定義時,最後會用`-j 1` #### ar命令 chatgpt ``` ar 是一個常用的命令行工具,主要用於創建、修改和提取靜態庫(static libraries)。靜態庫是一組已編譯的物件檔案(object files),可以在編譯時與應用程式鏈接,通常使用 .a 作為文件擴展名。 ``` 感覺很強大的工具,包含在bash中。 這是強大的工具。此處包含一個實驗 ``` // file1.c #include <stdio.h> void function1() { printf("Function 1\n"); } // file2.c #include <stdio.h> void function2() { printf("Function 2\n"); } gcc -c file1.c gcc -c file2.c ar rcs libmylib.a file1.o file2.o ar t libmylib.a ``` >file1.o file2.o ``` // file3.c #include <stdio.h> void function3() { printf("Function 3\n"); } gcc -c file3.c ar r libmylib.a file3.o ar t libmylib.a ``` >file1.o file2.o file3.o ``` ar d libmylib.a file1.o ar t libmylib.a ``` >file2.o file3.o ``` mkdir test2 cd test2 ar x ../libmylib.a ls ``` >file2.o file3.o :poop: :yum: :grin: :neutral_face: :nerd_face: :thinking_face: :exploding_head: :upside_down_face: :innocent: :airplane: :cityscape: :eye::lips::eye: :relaxed: :middle_finger: :lizard: :shark: :snake: :dolphin: :dragon: ``` 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇蛇 ``` #### 題外話: 常用的linux命令,此處不展開 chatgpt >join 用途:合併兩個按某一字段排序的文件。 例子:join file1 file2 xargs 用途:將標準輸入轉換為命令行參數。 例子:find . -name "*.txt" | xargs rm(刪除所有 .txt 文件) awk 用途:文本處理和報表生成的工具,可對文本進行模式匹配和處理。 例子:awk '{print $1}' filename(打印每行的第一欄) grep 用途:搜尋文本中符合模式的行。 例子:grep "pattern" filename sed 用途:流編輯器,可用於替換、刪除、插入文本。 例子:sed 's/old/new/g' filename #### shell的$(a || b) 當a0,返回a。 當a非0,返回b #### 正則表達式 chatgpt >基本和擴展正則表達式: grep:有兩種模式,基本正則表達式(BRE)和擴展正則表達式(ERE)。使用 grep 時,某些元字符在基本模式下需要轉義。 sed:使用基本正則表達式,若要使用擴展正則表達式,需要加上 -E 參數。 awk:使用擴展正則表達式。 元字符的使用: 在某些命令中,元字符的功能可能略有不同。例如,?、+、| 在基本正則表達式中可能需要轉義,而在擴展正則表達式中則不需要。 功能擴展: 不同命令提供的功能可能有所不同。例如,awk 支持更複雜的模式匹配和行處理功能,而 sed 更專注於流編輯。 引數的處理: 在命令中使用正則表達式時,不同的命令可能會有不同的引數處理方式,例如 sed 中的替換命令使用 s/pattern/replacement/ 的格式,而 awk 的格式則更為靈活。 正則表達式已經很陰間了,它還有兩種版本。:innocent: 此處不展開,[別人的文章](https://www.twle.cn/c/yufei/sed/sed-basic-regular-expressions.html) #### LZMA wiki >LZMA(英語:Lempel–Ziv–Markov chain algorithm)是2001年以來得到發展的一個資料壓縮演算法,它用於7-Zip歸檔工具中的7z格式和 Unix-like 下的 xz 格式。它使用類似於LZ77的字典編碼機制,在一般的情況下壓縮率比bzip2為高,用於壓縮的字典檔案大小可達4GB。 C++語言寫成的LZMA開放原始碼壓縮庫使用了區間編碼支援的LZ77改進壓縮演算法以及特殊的用於二進制的預處理程式。LZMA 對資料流、重複序列大小以及重續序列位置單獨進行了壓縮。LZMA支援幾種雜湊鏈變體、二元樹以及基數樹作為它的字典尋找演算法基礎。 #### xxHash [xxxHash github](https://github.com/Cyan4973/xxHash),不展開 #### LDFLAGS變量 還有問題 [csdn文章](https://blog.csdn.net/weixin_45842280/article/details/132912242) LDFLAGS可能是環境變量,我在hashcat makefile裡找不到別的LDFLAGS。 #### 筆記跳轉 跳過變量設置,直接看編譯,為了省事。 #### 正則表達式的範圍 只有部份工具支持,像是`grep`, `grep -E`支持擴展正則表達式, `sed`, `find -regex`, `vim`,且通常被包在`/aa/`中,常用的option是-E和--regexp,或者直接man,看看有沒有正則表達式。 #### .PHONY 實驗 ``` mkdir phonyTest cd phonyTest vim makefile .PHONY: clean clean: @echo "Clean" make clean ``` >Clean ``` vim makefile .PHONY: clean: @echo "Clean" make clean ``` >Clean ``` touch clean ``` >make: 'clean' is up to date. 這段實驗顯示了.PHONY如何避免clean命令在出現名為clean的文件後不工作的問題。換句話說,clean被設定成命令,而非文件。 #### .PHONY目標的.PHONY依賴項行為 ``` .PHONY: clean clean: $(RM) -f $(HASHCAT_FRONTEND) ... .PHONY: distclean distclean: clean $(RM) -f *.restore ... ``` 這段代碼中,當make distclean,會先執行clean 然後distclean,不會檢查文件的變更(因為.PHONY) #### makefile target list ``` .PHONY: default default: $(HASHCAT_FRONTEND) modules ``` ``` .PHONY: clean clean: ``` ``` .PHONY: distclean distclean: clean ``` ``` .PHONY: install install: install_docs install_shared install_tunings install_kernels install_modules install_hashcat ``` ``` .PHONY: install_make_library_dev_root install_make_library_dev_root: ``` ``` .PHONY: install_make_shared_root install_make_shared_root: ``` ``` .PHONY: install_docs install_docs: install_make_shared_root ``` ``` .PHONY: install_shared install_shared: install_make_shared_root ``` ``` .PHONY: install_tunings install_tunings: install_shared ``` ``` .PHONY: install_kernels install_kernels: install_shared ``` ``` .PHONY: install_modules install_modules: install_shared modules ``` ``` .PHONY: install_library install_library: $(HASHCAT_LIBRARY) ``` ``` .PHONY: install_library_dev install_library_dev: install_make_library_dev_root ``` ``` .PHONY: install_hashcat install_hashcat: $(HASHCAT_FRONTEND) ``` ``` .PHONY: uninstall uninstall: ``` ``` obj/%.NATIVE.o: src/%.c $(CC) -c $(CCFLAGS) $(CFLAGS_NATIVE) $< -o $@ -fpic ``` ``` obj/%.LZMA.NATIVE.o: $(DEPS_LZMA_PATH)/%.c $(CC) -c $(CCFLAGS) $(CFLAGS_NATIVE) $(CFLAGS_LZMA) $< -o $@ -fpic ``` ``` obj/%.ZLIB.NATIVE.o: $(DEPS_ZLIB_PATH)/%.c $(CC) -c $(CCFLAGS) $(CFLAGS_NATIVE) $(CFLAGS_ZLIB) $< -o $@ -fpic ``` ``` obj/%.XXHASH.NATIVE.o: $(DEPS_XXHASH_PATH)/%.c $(CC) -c $(CCFLAGS) $(CFLAGS_NATIVE) $< -o $@ -fpic ``` ``` obj/%.UNRAR.NATIVE.o: $(DEPS_UNRAR_PATH)/%.cpp $(CXX) -c $(CXXFLAGS) $(CFLAGS_NATIVE) $(CFLAGS_UNRAR) $< -o $@ -fpic ``` ``` obj/combined.NATIVE.a: $(NATIVE_OBJS) $(AR) rcs $@ $^ ``` ``` $(HASHCAT_LIBRARY): $(NATIVE_OBJS) $(CC) $^ -o $@ $(LFLAGS_NATIVE) -shared -Wl,-soname,$(HASHCAT_LIBRARY) ``` ``` $(HASHCAT_FRONTEND): src/main.c obj/combined.NATIVE.a $(CC) $(CCFLAGS) $(CFLAGS_NATIVE) $^ -o $@ $(LFLAGS_NATIVE) -DCOMPTIME=$(COMPTIME) -DVERSION_TAG=\"$(VERSION_TAG)\" -DINSTALL_FOLDER=\"$(INSTALL_FOLDER)\" -DSHARED_FOLDER=\"$(SHARED_FOLDER)\" -DDOCUMENT_FOLDER=\"$(DOCUMENT_FOLDER)\" ``` ``` modules/module_%.$(MODULE_SUFFIX): src/modules/module_%.c obj/combined.NATIVE.a $(CC) $(CCFLAGS) $(CFLAGS_NATIVE) $^ -o $@ $(LFLAGS_NATIVE) -shared -fPIC -D MODULE_INTERFACE_VERSION_CURRENT=$(MODULE_INTERFACE_VERSION) ``` ``` .PHONY: modules modules: $(MODULES_LIB) ``` ``` .PHONY: binaries binaries: linux win ``` ``` .PHONY: host_linux host_win host_linux: hashcat.bin host_win: hashcat.exe ``` ``` .PHONY: linux win linux: host_linux modules_linux win: host_win modules_win ``` ``` obj/%.LINUX.o: src/%.c $(CC_LINUX) $(CCFLAGS) $(CFLAGS_CROSS_LINUX) -c -o $@ $< ``` ``` obj/%.WIN.o: src/%.c $(CC_WIN) $(CCFLAGS) $(CFLAGS_CROSS_WIN) -c -o $@ $< ``` ``` obj/%.LZMA.LINUX.o: $(DEPS_LZMA_PATH)/%.c $(CC_LINUX) $(CCFLAGS) $(CFLAGS_CROSS_LINUX) $(CFLAGS_LZMA) -c -o $@ $< ``` ``` obj/%.LZMA.WIN.o: $(DEPS_LZMA_PATH)/%.c $(CC_WIN) $(CCFLAGS) $(CFLAGS_CROSS_WIN) $(CFLAGS_LZMA_WIN) -c -o $@ $< ``` ``` obj/%.ZLIB.LINUX.o: $(DEPS_ZLIB_PATH)/%.c $(CC_LINUX) $(CCFLAGS) $(CFLAGS_CROSS_LINUX) $(CFLAGS_ZLIB) -c -o $@ $< ``` ``` obj/%.ZLIB.WIN.o: $(DEPS_ZLIB_PATH)/%.c $(CC_WIN) $(CCFLAGS) $(CFLAGS_CROSS_WIN) $(CFLAGS_ZLIB) -c -o $@ $< ``` ``` obj/%.XXHASH.LINUX.o: $(DEPS_XXHASH_PATH)/%.c $(CC_LINUX) $(CCFLAGS) $(CFLAGS_CROSS_LINUX) -c -o $@ $< obj/%.XXHASH.WIN.o: $(DEPS_XXHASH_PATH)/%.c $(CC_WIN) $(CCFLAGS) $(CFLAGS_CROSS_WIN) -c -o $@ $< ``` ``` obj/%.UNRAR.LINUX.o: $(DEPS_UNRAR_PATH)/%.cpp $(CXX_LINUX) $(CXXFLAGS) $(CFLAGS_CROSS_LINUX) $(CFLAGS_UNRAR) -c -o $@ $< ``` ``` obj/%.UNRAR.WIN.o: $(DEPS_UNRAR_PATH)/%.cpp $(CXX_WIN) $(CXXFLAGS) $(CFLAGS_CROSS_WIN) $(CFLAGS_UNRAR_WIN) -c -o $@ $< ``` ``` obj/combined.LINUX.a: $(LINUX_OBJS) $(AR_LINUX) rcs $@ $^ ``` ``` obj/combined.WIN.a: $(WIN_OBJS) $(AR_WIN) rcs $@ $^ ``` ``` hashcat.bin: src/main.c obj/combined.LINUX.a $(CC_LINUX) $(CCFLAGS) $(CFLAGS_CROSS_LINUX) -o $@ $^ $(LFLAGS_CROSS_LINUX) -DCOMPTIME=$(COMPTIME) -DVERSION_TAG=\"$(VERSION_TAG)\" -DINSTALL_FOLDER=\"$(INSTALL_FOLDER)\" -DSHARED_FOLDER=\"$(SHARED_FOLDER)\" -DDOCUMENT_FOLDER=\"$(DOCUMENT_FOLDER)\" ``` ``` hashcat.exe: src/main.c obj/combined.WIN.a $(WIN_ICONV)/lib/libiconv.a $(CC_WIN) $(CCFLAGS) $(CFLAGS_CROSS_WIN) -o $@ $^ $(LFLAGS_CROSS_WIN) -DCOMPTIME=$(COMPTIME) -DVERSION_TAG=\"$(VERSION_TAG)\" ``` ``` hashcat.dll: src/main.c obj/combined.WIN.a $(WIN_ICONV)/lib/libiconv.a $(CC_WIN) $(CCFLAGS) $(CFLAGS_CROSS_WIN) -o $@ $^ $(LFLAGS_CROSS_WIN) -DCOMPTIME=$(COMPTIME) -DVERSION_TAG=\"$(VERSION_TAG)\" -shared ``` #### shell和makefile的關係 chatgpt ``` 在 Makefile 裡面,你可以使用部分的 shell 語法和功能,但不能直接像在命令行那樣完整使用所有功能。Makefile 有自己的一些限制和特定的處理方式。這裡是具體的幾點區別和注意事項: 1. $(shell ...) 語法 Makefile 允許你使用 $(shell ...) 語法來執行 shell 命令,並將命令的輸出作為變量值。例如: makefile CURRENT_DIR := $(shell pwd) 這會將當前目錄的路徑賦值給變量 CURRENT_DIR。 2. 命令執行行 在 Makefile 的目標 (target) 規則中,命令行前面需要有一個 Tab 縮排。每一行命令默認會被 Makefile 交給 shell 執行。例如: makefile all: echo "Hello, World" 這裡的 echo 會被傳遞給 shell 執行。 3. 命令不完整支持 雖然 Makefile 支持大部分基本的 shell 功能(如 echo, ls, cd 等),但並不是所有功能都完全支持。例如: 變量作用域:Makefile 的每一行命令會在單獨的 shell 中執行,這意味著像 cd 這樣改變當前工作目錄的命令,只會對當前命令有效。例如,這段代碼不會如你預期地進入目錄: makefile all: cd some_directory echo "Current directory: $(shell pwd)" 在這種情況下,cd 只在第一行有效,後面的 echo 還是在原目錄執行。解決辦法是將命令寫在同一行,或者使用 &&: makefile all: cd some_directory && echo "Current directory: $(shell pwd)" 4. 內建的變量和函數 Makefile 具有自己的一些內建變量和函數,像 $(shell ...), $(wildcard ...), $(foreach ...) 等,這些功能與 shell 不完全一樣,需要按照 Makefile 特有的語法來使用。 5. 條件判斷和循環 Makefile 也支持基本的條件語句(ifeq, ifneq)和循環($(foreach ...)),但它們的語法和 shell 是不同的。這些都是 Makefile 自己的語法,而不是直接使用 shell 的功能。 總結: Makefile 可以使用部分 shell 功能,但受到一定限制: 可以用 $(shell ...) 語法來捕捉 shell 命令的輸出。 目標規則中的命令是逐行執行的,每行命令都在新的 shell 實例中執行。 不能完整使用所有 shell 語法,特別是跨行的變量作用域。 如果你需要更強大的 shell 支持,可以考慮將複雜的命令邏輯寫在一個 .sh 腳本中,並在 Makefile 中調用這個腳本。 ``` #### .a和.so的差別和規則 .a就是.lib .so就是.dll 兩者的名字被規定以lib開頭,因為kernal的找lib的方式就是看開頭(option -lmylib會讓kernal找libmylib)。