久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

linux中gmake怎么調用

161次閱讀
沒有評論

共計 13371 個字符,預計需要花費 34 分鐘才能閱讀完成。

本篇內容主要講解“linux 中 gmake 怎么調用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓丸趣 TV 小編來帶大家學習“linux 中 gmake 怎么調用”吧!

在 linux 中,gmake 就是 GUN make,是一種流行的、常用的用于構建 C 語言軟件的程序,用于構建 Linux 內核和其他常用的 GNU/Linux 程序和軟件庫。GNU Make 是一個可以自動運行 shell 命令并幫助執行重復任務的程序;它通常用于將文件轉換成其他形式,例如將源代碼文件編譯成程序或庫。

gmake 就是 GUN make,因為在 linux 外的平臺上,make 一般被占用了,所以 GUN make 只好叫 gmake 了。

GNU Make 是一種流行的、常用的用于構建 C 語言軟件的程序。用于構建 Linux 內核和其他常用的 GNU/Linux 程序和軟件庫。

大多數嵌入式軟件開發人員在職業生涯中的某個時候都會使用 GNU Make,要么使用它來編譯小型庫,要么構建整個項目。盡管有很多很多的選項可以替代 Make,但是由于它的特性集和廣泛的支持,它仍然通常被選擇為新軟件的構建系統。

什么是 GNU Make?

GNU Make 是一個可以自動運行 shell 命令并幫助執行重復任務的程序。它通常用于將文件轉換成其他形式,例如將源代碼文件編譯成程序或庫。

它通過跟蹤先決條件和執行命令層次結構來生成目標來實現這一點。

何時選擇 Make

Make 適用于構建小型 C / c++ 項目或庫,這些項目或庫將包含在另一個項目的構建系統中。大多數構建系統都有辦法集成基于 make 的子項目。

對于較大的項目,您會發現更現代的構建系統更易于使用。

在以下情況下,我建議使用非 Make 的構建系統:

當正在構建的目標 (或文件) 數量為 (或最終將為) 數百時。需要一個“配置”步驟,它設置和保存變量、目標定義和環境配置。該項目將保持內部或私有,將不需要由終端用戶構建。您會發現調試是一項令人沮喪的工作。您需要構建的是跨平臺的,可以在 macOS、Linux 和 Windows 上構建。在這些情況下,您可能會發現使用 CMake、Bazel、Meson 或其他現代構建系統是一種更愉快的體驗。

調用 Make

運行 make 將從當前目錄加載一個名為 Makefile 的文件,并嘗試更新默認目標(稍后會詳細介紹目標)。

Make 將依次搜索名為 GNUmakefile、makefile 和 makefile 的文件

你可以使用 -f/——file 參數指定一個特定的 makefile:

$ make -f foo.mk 你可以指定任意數量的目標,列出它們作為位置參數:

# 典型目標 $ make clean all 你可以用 - C 參數傳遞 Make 目錄,它會運行 Make,就像它首先被 cd 到那個目錄一樣。

$ make -C some/sub/directory 有趣的事實:git 也可以和 - C 一起運行,達到同樣的效果!

并行調用

如果提供 - j 或 - l 選項,Make 可以并行運行作業。我被告知的一個指導原則是,將作業限制設置為處理器核心數量的 1.5 倍:

#a machine with 4 cores: make -j make -j 有趣的是,我發現使用 -l“負載限制”選項的 CPU 利用率比使用 -j“工作”選項略好。盡管 YMMV !

有幾種方法可以通過編程方式找到當前機器的 CPU 計數。一個簡單的方法是使用 python multiprocessing.cpu_count()函數來獲得支持的系統的線程數量(注意與超線程系統, 這將消耗大量的計算機資源, 但可能是更可取的讓讓產生無限的工作)。

# 在子 shell 中調用 python 的 cpu_count()函數 make -l (python -c import multiprocessing;print (multiprocessing.cpu_count())”)

并行調用期間的輸出

如果 Make 正在并行執行的命令有大量輸出,您可能會看到在 stdout 上交錯輸出。為了處理這個問題,Make 有一個選項——output -sync。

我建議使用——output-sync=recurse,它將在每個目標完成時打印 recipe 的全部輸出,而不會分散其他 recipe 輸出。

如果 recipe 使用遞歸 Make,它還將一起輸出整個遞歸 Make 的輸出。

對 Makefile 的剖析 Makefile 包含用于生成目標的規則。Makefile 的一些基本組件如下所示:

#Comments are prefixed with the # symbol

#A variable assignment
FOO = hello there!

#A rule creating target test , with test.c as a prerequisite
test: test.c
# The contents of a rule is called the recipe , and is
# typically composed of one or more shell commands.
# It must be indented from the target name (historically with
# tabs, spaces are permitted)

# Using the variable FOO
echo $(FOO)

# Calling the C compiler using a predefined variable naming
# the default C compiler, $(CC)
$(CC) test.c -o test

讓我們看看上面例子的每個部分。

變量

變量使用語法 $(FOO),其中 FOO 是變量名。

變量包含純字符串,因為 Make 沒有其他數據類型。附加到一個變量將添加一個空格和新的內容:

FOO = one
FOO += two
# FOO is now one two

FOO = one
FOO = $(FOO)two
# FOO is now onetwo

變量賦值

在 GNU Make 語法中,變量的賦值方式有兩種:

右邊的表達式是逐字賦值給變量的——這很像 C / c++ 中的宏,在使用變量時對表達式求值:

FOO = 1
BAR = $(FOO)
FOO = 2
# prints BAR=2
$(info BAR=$(BAR))

將一個表達式的結果賦值給一個變量; 表達式在賦值時展開:

FOO = 1
BAR := $(FOO)
FOO = 2
# prints BAR=1
$(info BAR=$(BAR))

注意: 上面的 $(info…)函數用于打印表達式,在調試 makefile 時非常方便!*’

未顯式、隱式或未自動設置的變量將計算為空字符串。

環境變量

環境變量被攜帶到 Make 執行環境中。以下面的 makefile 為例:

$(info YOLO variable = $(YOLO))

如果我們在運行 make 時在 shell 命令中設置了變量 YOLO,我們將設置這個值:

$ YOLO= hello there! make
YOLO variable = hello there!
make: *** No targets.  Stop.

注意:Make 打印“No targets”錯誤,因為我們的 makefile 沒有列出目標!

如果你使用?= 賦值語法,Make 只會在變量沒有值的情況下賦值:

Makefile:

# 默認 CC 為 gcc
CC ? = gcc

然后我們可以重寫 makefile 中的 $(CC):

$ CC=clang make

另一個常見的模式是允許插入額外的標志。在 makefile 中,我們將追加變量而不是直接賦值給它。

CFLAGS += -Wall

這允許從環境中傳入額外的標志:

$ CFLAGS= -Werror=conversion -Werror=double-promotion  make

這是非常有用的!

最重要的變量

變量使用的一個特殊類別稱為覆蓋變量。使用此命令行選項將覆蓋設置在環境中的或 Makefile 中的值!

Makefile:

# any value set elsewhere
YOLO = not overridden
$(info $(YOLO))

命令:

# setting YOLO to different values in the environment + makefile + overriding
# variable, yields the overriding value
$ YOLO= environment set make YOLO= overridden!!
overridden!!
make: *** No targets.  Stop.

有針對性的變量

這些變量僅在 recipe 上下文中可用。它們也適用于任何必備配方!

# set the -g value to CFLAGS
# applies to the prog.o/foo.o/bar.o recipes too!
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
echo $(CFLAGS) # will print -g

隱式變量

這些都是由 Make 預先定義的(除非用同名的任何其他變量類型重寫)。一些常見的例子:

$(CC) - the C compiler (gcc)
$(AR) - archive program (ar)
$(CFLAGS) - flags for the C compiler

自動變量

這些是由 Make 設置的特殊變量,在 recipe 上下文中可用。它們對于防止重復的名字很有用(Don t Repeat Yourself)。

一些常見的自動變量:

# $@ : the target name, here it would be test.txt 
test.txt:
echo HEYO $@

# $^ : name of all the prerequisites
all.zip: foo.txt test.txt
# run the gzip command with all the prerequisites $^ , outputting to the
# name of the target, $@
gzip -c $^ $@
See more at: https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html

目標(目標)

目標是規則語法的左邊:

arget: prerequisite
recipe

target 幾乎總是命名文件。這是因為 Make 使用最后修改時間來跟蹤 target 是否比其 prerequistite 更新或更早,以及是否需要重新構建它!

當調用 Make 時,你可以通過將其指定為位置參數來指定想要構建的 target:

# make the test.txt and all.zip targets
make test.txt all.zip

如果您沒有在命令中指定目標,Make 將使用 makefile 中指定的第一個目標,稱為“默認目標”(如果需要,也可以覆蓋默認目標)。

虛假 phony 目標

有時候設置元目標是很有用的,比如 all, clean, test 等等。在這些情況下,您不希望 Make 檢查名為 all/clean 等的文件。

Make 提供.PHONY 目標語法,將目標標記為不指向文件:

假設我們的項目構建了一個程序和一個庫 foo 和 foo.a; 如果我們想要 在默認情況下,我們可以創建一個 all 規則來構建兩者 .PHONY:all all : foo foo.a

如果你有多個假目標,一個好的模式可能是將每個目標都附加到定義它的.PHONY 中:

# the all rule that builds and tests. Note that it s listed first to make it
# the default rule
.PHONY: all
all: build test

# compile foo.c into a program foo
foo: foo.c
$(CC) foo.c -o foo

# compile foo-lib.c into a library foo.a
foo.a: foo-lib.c
# compile the object file
$(CC) foo-lib.c -c foo-lib.o
# use ar to create a static library containing our object file. using the
# $@ variable here to specify the rule target foo.a
$(AR) rcs $@ foo-lib.o

# a phony rule that builds our project; just contains a prerequisite of the
# library + program
.PHONY: build
build: foo foo.a

# a phony rule that runs our test harness. has the build target as a
# prerequisite! Make will make sure (pardon the pun) the build rule executes
# first
.PHONY: test
test: build
./run-tests.sh

請注意! !. phony 目標總是被認為是過期的,因此 Make 將總是運行這些目標的配方 (因此也運行任何具有. phony 先決條件的目標!) 小心使用! !

隱式規則

隱含規則由 Make 提供。我發現使用它們會讓人感到困惑,因為在幕后發生了太多的行為。你偶爾會在野外遇到它們,所以要小心。

# this will compile test.c with the default $(CC), $(CFLAGS), into the program
# test . it will handle prerequisite tracking on test.c
test: test.o

模式的規則

模式規則允許你編寫一個通用規則,通過模式匹配應用于多個目標:

# Note the use of the $ automatic variable, specifying the first
# prerequisite, which is the .c file
%.o: %.c
$(CC) -c $ -o $@

or

OBJ_FILES = foo.o bar.o

# Use CC to link foo.o + bar.o into program . Note the use of the $^
# automatic variable, specifying ALL the prerequisites (all the OBJ_FILES)
# should be part of the link command
program: $(OBJ_FILES)
   $(CC) -o $@ $^

先決條件

如上所述,Make 將在運行規則之前檢查這些目標。它們可以是文件或其他目標。

如果任何先決條件比目標更新(修改時間),Make 將運行目標規則。

在 C 項目中,你可能有一個將 C 文件轉換為目標文件的規則,如果 C 文件發生變化,你希望目標文件重新生成:

foo.o: foo.c
# use automatic variables for the input and output file names
$(CC) $^ -c $@

自動的先決條件

對于 C 語言項目來說,一個非常重要的考慮是,如果 C 文件的 #include 頭文件發生了變化,那么將觸發重新編譯。這是通過 gcc/clang 的 - M 編譯器標志完成的,它將輸出一個.d 文件,然后用 Make include 指令導入。

.d 文件將包含.c 文件的必要先決條件,因此任何頭文件的更改都會導致重新構建。

基本形式可能是:

# these are the compiler flags for emitting the dependency tracking file. Note
# the usage of the $ automatic variable
DEPFLAGS = -MMD -MP -MF $ .d

test.o: test.c
   $(CC) $(DEPFLAGS) $ -c $@

# bring in the prerequisites by including all the .d files. prefix the line with
# - to prevent an error if any of the files do not exist
-include $(wildcard *.d)

Order-only 先決條件

這些先決條件只有在不存在的情況下才會構建; 如果它們比目標更新,則不會觸發目標重新構建。

典型的用法是為輸出文件創建一個目錄; 將文件發送到目錄將更新其 mtime 屬性,但我們不希望由此觸發重新構建。

OUTPUT_DIR = build

# output the .o to the build directory, which we add as an order-only
# prerequisite- anything right of the | pipe is considered order-only
$(OUTPUT_DIR)/test.o: test.c | $(OUTPUT_DIR)
$(CC) -c $^ -o $@

# rule to make the directory
$(OUTPUT_DIR):
mkdir -p $@

recipe

“recipe”是創建目標時要執行的 shell 命令列表。它們被傳遞到子 shell 中(默認為 /bin/sh)。如果 target 在 recipe 運行后更新,則認為規則是成功的(但如果沒有更新,則不視為錯誤)。

foo.txt:
# a simple recipe
echo HEYO $@

如果配方中的任何一行返回非零退出代碼,Make 將終止并打印一條錯誤消息。你可以通過前綴 - 字符來告訴 Make 忽略非零退出碼:

.PHONY: clean
clean:
# we don t care if rm fails
-rm -r ./build

在 recipe 行前面加上 @將禁止在執行之前 echo 該行:

clean:
@# this recipe will just print About to clean everything!
@# prefixing the shell comment lines # here also prevents them from
@# appearing during execution
@echo About to clean everything!

Make 會在運行 recipe 上下文中展開變量 / 函數表達式,但不會處理它。如果你想訪問 shell 變量,請使用 $:

USER = linus

print-user:
# print out the shell variable $USER
echo $$USER

# print out the make variable USER
echo $(USER)

function

Make 函數的調用語法如下:

$(function-name arguments) 其中 arguments 是用逗號分隔的參數列表。

For example:

FILES=$(wildcard *.c)

# you can combine function calls; here we strip the suffix off of $(FILES) with
# the $(basename) function, then add the .o suffix
O_FILES=$(addsuffix .o,$(basename $(FILES)))

# note that the GNU Make Manual suggests an alternate form for this particular
# operation:
O_FILES=$(FILES:.c=.o)

用戶定義函數

reverse = $(2) $(1)

foo = $(call reverse,a,b)

# recursive wildcard (use it instead of $(shell find . -name *.c))
# taken from https://stackoverflow.com/a/18258352
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))

C_FILES = $(call rwildcard,.,*.c)

shell 函數

你可以讓 Make 調用一個 shell 表達式并捕獲結果:

TODAYS_DATE=$(shell date –iso-8601)

不過,我在使用這個功能時很謹慎; 它會增加對你使用的任何程序的依賴,所以如果你正在調用更奇特的程序,確保你的構建環境是受控的(例如在容器中或使用 Conda)。

make 的條件表達式

FOO=yolo
ifeq ($(FOO),yolo)
$(info foo is yolo!)
else
$(info foo is not yolo :()
endif

# testing if a variable is set; unset variables are empty
ifneq ($(FOO),)  # checking if FOO is blank
$(info FOO is unset)
endif

# complex conditional
ifeq ($(FOO),yolo)
$(info foo is yolo)
else ifeq ($(FOO), heyo)
$(info foo is heyo)
else
$(info foo is not yolo or heyo :()
endif

make include

sources.mk:

SOURCE_FILES :=
bar.c
foo.c \

Makefile:

include sources.mk

OBJECT_FILES = $(SOURCE_FILES:.c=.o)

%.o: %.c (CC) -c ^ -o $@

make eval

# generate rules for xml- json in some weird world
FILES = $(wildcard inputfile/*.xml)

# create a user-defined function that generates rules
define GENERATE_RULE =
$(eval
# prereq rule for creating output directory
$(1)_OUT_DIR = $(dir $(1))/$(1)_out
$(1)_OUT_DIR:
mkdir -p $@

# rule that calls a script on the input file and produces $@ target
$(1)_OUT_DIR/$(1).json: $(1) | $(1)_OUT_DIR
./convert-xml-to-json.sh $(1) $@
)

# add the target to the all rule
all: $(1)_OUT_DIR/$(1).json
endef

# produce the rules
.PHONY: all
all:

$(foreach file,$(FILES),$(call GENERATE_RULE,$(file)))

請注意,使用 Make 的這個特性的方法可能會讓人很困惑,添加一些有用的注釋來解釋意圖是什么,對您未來的自己會很有用!

VPATH

VPATH 是一個特殊的 Make 變量,它包含 Make 在查找先決條件和目標時應該搜索的目錄列表。

它可以用來將對象文件或其他派生文件發送到./build 目錄中,而不是把 src 目錄弄得亂七八糟:

# This makefile should be invoked from the temporary build directory, eg:
# $ mkdir -p build cd ./build make -f ../Makefile

# Derive the directory containing this Makefile
MAKEFILE_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

# now inform Make we should look for prerequisites from the root directory as
# well as the cwd
VPATH += $(MAKEFILE_DIR)

SRC_FILES = $(wildcard $(MAKEFILE_DIR)/src/*.c)

# Set the obj file paths to be relative to the cwd
OBJ_FILES = $(subst $(MAKEFILE_DIR)/,,$(SRC_FILES:.c=.o))

# now we can continue as if Make was running from the root directory, and not a
# subdirectory

# $(OBJ_FILES) will be built by the pattern rule below
foo.a: $(OBJ_FILES)
$(AR) rcs $@ $(OBJ_FILES)

# pattern rule; since we added ROOT_DIR to VPATH, Make can find prerequisites
# like `src/test.c` when running from the build directory!
%.o: %.c
# create the directory tree for the output file  
echo $@
mkdir -p $(dir $@)
# compile
$(CC) -c $^ -o $@

touch file

# our tools are stored in tools.tar.gz, and downloaded from a server
TOOLS_ARCHIVE = tools.tar.gz
TOOLS_URL = https://httpbin.org/get

# the rule to download the tools using wget
$(TOOLS_ARCHIVE):
wget $(TOOLS_URL) -O $(TOOLS_ARCHIVE)

# rule to unpack them
tools-unpacked.dummy: $(TOOLS_ARCHIVE)
# running this command results in a directory.. but how do we know it
# completed, without a file to track?
tar xzvf $^
# use the touch command to record completion in a dummy file
touch $@

調試 makefile

對于小問題,我通常使用 printf 的 Make 等效函數,即 $(info/warning/error)函數,例如當檢查不工作的條件路徑時:

ifeq ($(CC),clang)
$(error whoops, clang not supported!)
endif

verbose flag

# Makefile for building the example binary from C sources

# Verbose flag
ifeq ($(V),1)
Q :=
else
Q := @
endif

# The build folder, for all generated output. This should normally be included
# in a .gitignore rule
BUILD_FOLDER := build

# Default all rule will build the example target, which here is an executable
.PHONY:
all: $(BUILD_FOLDER)/example

# List of C source files. Putting this in a separate variable, with a file on
# each line, makes it easy to add files later (and makes it easier to see
# additions in pull requests). Larger projects might use a wildcard to locate
# source files automatically.
SRC_FILES = \
   src/example.c \
   src/main.c

# Generate a list of .o files from the .c files. Prefix them with the build
# folder to output the files there
OBJ_FILES = $(addprefix $(BUILD_FOLDER)/,$(SRC_FILES:.c=.o))

# Generate a list of depfiles, used to track includes. The file name is the same
# as the object files with the .d extension added
DEP_FILES = $(addsuffix .d,$(OBJ_FILES))

# Flags to generate the .d dependency-tracking files when we compile.  It s
# named the same as the target file with the .d extension
DEPFLAGS = -MMD -MP -MF $@.d

# Include the dependency tracking files
-include $(DEP_FILES)

# List of include dirs. These are put into CFLAGS.
INCLUDE_DIRS = \
   src/

# Prefix the include dirs with -I when passing them to the compiler
CFLAGS += $(addprefix -I,$(INCLUDE_DIRS))

# Set some compiler flags we need. Note that we re appending to the CFLAGS
# variable
CFLAGS += \
   -std=c11 \
   -Wall \
   -Werror \
   -ffunction-sections -fdata-sections \
   -Og \
   -g3

# Our project requires some linker flags: garbage collect sections, output a
# .map file
LDFLAGS += \
   -Wl,--gc-sections,-Map,$@.map

# Set LDLIBS to specify linking with libm, the math library
LDLIBS += \
   -lm

# The rule for compiling the SRC_FILES into OBJ_FILES
$(BUILD_FOLDER)/%.o: %.c
@echo Compiling $(notdir $)
@# Create the folder structure for the output file
@mkdir -p $(dir $@)
$(Q) $(CC) $(CFLAGS) $(DEPFLAGS) -c $ -o $@

# The rule for building the executable example , using OBJ_FILES as
# prerequisites. Since we re not relying on an implicit rule, we need to
# explicity list CFLAGS, LDFLAGS, LDLIBS
$(BUILD_FOLDER)/example: $(OBJ_FILES)
@echo Linking $(notdir $@)
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

# Remove debug information for a smaller executable. An embedded project might
# instead using [arm-none-eabi-]objcopy to convert the ELF file to a raw binary
# suitable to be written to an embedded device
STRIPPED_OUTPUT = $(BUILD_FOLDER)/example-stripped

$(STRIPPED_OUTPUT): $(BUILD_FOLDER)/example
@echo Stripping $(notdir $@)
$(Q)objcopy --strip-debug $^ $@

# Since all our generated output is placed into the build folder, our clean rule
# is simple. Prefix the recipe line with - to not error if the build folder
# doesn t exist (the -f flag for rm also has this effect)
.PHONY: clean
clean:
- rm -rf $(BUILD_FOLDER)

$ V=1 make

make 建議

讓 Make 發揮最大作用的建議列表:

target 通常應該是真實的文件。當發出子 MAKE 命令時,總是使用 (MAKE)。盡量避免使用.phony 目標。如果規則生成任何文件工件,請考慮將其作為目標,而不是冒名! 盡量避免使用隱含的規則。對于 C 文件,確保使用.d 自動包括跟蹤! 小心使用元編程。在規則中使用自動變量。總是嘗試使用 @作為菜譜輸出路徑,這樣你的規則和 Make 的路徑就完全相同了。在 makefile 中自由地使用注釋,特別是在使用了復雜的行為或微妙的語法時。你的同事(還有未來的自己) 會感謝你的。使用 - j 或 - l 選項并行運行 Make ! 盡量避免使用 touch 命令來跟蹤規則完成。

到此,相信大家對“linux 中 gmake 怎么調用”有了更深的了解,不妨來實際操作一番吧!這里是丸趣 TV 網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-13發表,共計13371字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 富平县| 永宁县| 类乌齐县| 洪湖市| 富平县| 哈尔滨市| 无棣县| 商水县| 武陟县| 历史| 昭通市| 江华| 毕节市| 漳州市| 临沧市| 望奎县| 茌平县| 化德县| 江西省| 安陆市| 神木县| 莎车县| 固阳县| 姜堰市| 友谊县| 泰顺县| 连江县| 东山县| 临泉县| 桐乡市| 灵台县| 诸城市| 凤山市| 芷江| 怀宁县| 孝感市| 黔西| 无极县| 乌兰县| 淄博市| 漾濞|