5

私はコンピューター工学の学生で、実装する C プログラムがもう 1 つあります。これまでは、以前のプロジェクトから常に新しい Makefile を作成していましたが、毎回セットアップに時間がかかりました。メイン関数を含む c ファイルの名前だけを提供する必要があるほど強力な Makefile キャンバスを使用できますか?

私の考えは、新しいプロジェクトごとに、それを含むMakefileフォルダー、bin フォルダー、および src フォルダーを作成することです。main()次に、いくつかの変数を Makefile (関数を含む C ファイル) に編集makeし、依存関係を考慮してすべてを自動的に構築します。

Makefileそのようなものが存在するかどうか知っていますか?

[Alexandre C. による編集] : Automake/Autoconf は、標準ライブラリのみを使用し、標準の UNIX OS で実行されるこの種のプロジェクトにとってはやり過ぎです。実装する必要があるプロジェクトの場合、(リンクされるファイルの) 依存関係は常に ".h" インクルードから推測でき、通常、関連するファイルはほとんどありません。

4

7 に答える 7

3

魔法のような完璧なものに最も近いのMakefileは、ポータブルCプログラムとライブラリのデファクトスタンダードであるAutomakeを使用することです。

このページから持ち上げた例として、これはMakefile.amに追加するものの例です。

bin_PROGRAMS = zardoz
zardoz_SOURCES = main.c head.c float.c vortex9.c gun.c
zardoz_LDADD = $(LIBOBJS)

ここで追加するmakeターゲットに相当するものはと呼ばれzardozます。ソースはで指定されzardoz_SOURCES、リンクする必要のある追加のライブラリはで指定されzardoz_LDADDます。mainリンカはリンク段階でこれを自動的に検出するため、関数が存在する場所を指定する必要はありません。それが存在しない場合、リンクは単に失敗します。

于 2012-10-10T14:26:18.063 に答える
1

これを行う独自のマクロ「パッケージ」を簡単に作成できます。たとえば、このファイルをボイラープレートとして作成し、それを呼び出してprogram.mk、ツリー内の中央の場所に配置します。

lang.c.objs   = $(patsubst %.c,%.o,$(1))
lang.c.link   = $(CC) $(CFLAGS) $(LDFLAGS) -o $(1) $(2)
lang.c++.objs = $(patsubst %.cpp,%.o,$(1))
lang.c++.link = $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(1) $(2)

define make-program
  program.$(1).lang    ?= c
  program.$(1).objects ?= $$(call lang.$$(program.$(1).lang).objs,$$(program.$(1).sources))
  $$(program.$(1).name): $$(program.$(1).objects) $$(program.$(1).extra-deps)
      $$(call lang.$$(program.$(1).lang).link,$$@,$$^ $$(program.$(1).ldlibs))
  CLEANABLE    += $$(program.$(1).name)
  ALL_PROGRAMS += $$(program.$(1).name)
endef

# If the user didn't specify a list of programs, build them all
ifndef PROGRAMS
  PROGRAMS = $(foreach p,$(filter program.%.name,$(.VARIABLES)),\
    $(patsubst program.%.name,%,$(p)))
endif

# Generate the rule to build each program
$(foreach p,$(PROGRAMS),$(eval $(call make-program,$(p))))

.PHONY: all clean
all: $(ALL_PROGRAMS)

clean: ; rm -f $(CLEANABLE)

.DEFAULT_GOAL := all

ここで、プログラムをビルドする各ディレクトリで、makefile を次のようにすることができます。

program.p.name    = Program
program.p.sources = Program1.c Program2.c

include path/to/program.mk

同様のものlibrary.mkをライブラリにも使用できます。このアプローチは非常に強力で、拡張が非常に簡単です。

于 2012-10-10T16:47:57.557 に答える
0

autoconfを使用する./configureと、最もオープンソースのプロジェクトと同じように、有名なコマンドでMakefileを自動的に生成できます。このリンクを参照してください:makefileを生成するようにファイルテンプレートを設定します

于 2012-10-10T15:07:40.187 に答える
0

標準の UNIX 環境に興味があるなら、POSIXmakeが提供するものに固執してみませんか?

# Lean and mean.
.POSIX:

CFLAGS = -DNDEBUG -O
LDFLAGS = -s

TARGETS = abc def

all: $(TARGETS)

clean:
    rm -f $(TARGETS)

# Some dependencies.
abc: def.h

# Some special rules.
def: def.c
    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ def.c -l m

ほとんどの小さなプロジェクトでは、デフォルトより複雑なものは必要ありません。おそらく、複雑なメイクファイル ロジックを記述して時間を無駄にするのではなく、プロジェクト自体に集中する必要があります。

POSIX の制限の 1 つmakeは、パターン ルールがなく、サフィックス ルールがディレクトリを処理できないことです。したがって、ソース ファイルを異なるディレクトリに分散するには、ファイルごとに 1 つのルールを適用するか、再帰的に作成する必要があります。個人的には、小さなプロジェクトの場合、わざわざソース ファイルを別の場所に移動することはありません。POSIX に固執することで、他の POSIX 互換ビルド システム (たとえばmakeBSD ) 間での移植性も提供されます。make

依存関係の自動計算については、 を参照してくださいgcc -M。依存関係ルールを含むメイクファイルを生成します。includeその後、メイクファイルでそれらを使用できます。ただし、私の意見では、すべての重要な依存関係を 1 つのヘッダー ファイルで追跡し、すべてのファイルがサフィックス ルールによってこのヘッダーに依存するようにすることをお勧めします。それほど面倒ではありませんが、移植性はいくらか節約できます。

要約すると、私の提案は、合併症について過度に心配することを避けることです. 彼らが報われることはめったにありません。特に、私は が好きだったことは一autotools度もありません。UNIX はシンプルさがすべてです。不必要に複雑にすることは、UNIX の精神に反します。:)

于 2012-10-16T06:04:39.453 に答える
0

私は次の解決策を思いつきました:

# Author Matthieu Sieben (http://matthieusieben.com)
# Version 23/10/2012
#
# This Makefile is licensed under the Creative Commons Attribution
# Partage dans les Mêmes Conditions 2.0 Belgique License.
# To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.0/be/.
# Use at your own risk.
#
# Use Makefile.inc to write you own rules or to overwrite the default values defined here.

SRCDIR  = ./src
BINDIR  = ./bin

SHELL   = /bin/bash
CC      = /usr/bin/gcc
LIBS    =
CFLAGS  = -Wall -Wextra -Werror
LDFLAGS =

.PHONY: default all clean distclean
.SUFFIXES: .c .o

# make "all" the default target
default: all

-include Makefile.inc
-include Makefile.d

CFLAGS += -I$(SRCDIR)
ifeq ($(DEBUG), 1)
    CFLAGS += -DDEBUG=1 -ggdb
else
    CFLAGS += -DDEBUG=0 -O2
    LDFLAGS += -O2
endif

%.o: %.c
    @echo "  Compiling `basename $<`";
    @$(CC) $(CFLAGS) -o $@ -c $<;

clean:
    @echo "Cleaning compiled files";
    @find $(SRCDIR) -name "*.o" -exec rm {} \;
    @[ -e Makefile.d ] && rm Makefile.d;

distclean: clean
    @echo "Removing executables";
    @find $(BINDIR) -type f -exec rm {} \;

Makefile.d: $(shell find $(SRCDIR) -type f -name "*.c")
    @echo "Building dependencies";
    @for file in `find $(SRCDIR) -name "*.c" -print`; do\
        $(CC) $(CFLAGS) -MM -MT $${file/%.c/.o} $$file | tr -d "\n\\" >> Makefile.d.tmp;\
        echo -e "\n" >> Makefile.d.tmp;\
    done;\
    for file in `find $(SRCDIR) -name "*.c" -exec grep -Hs "main(" {} \; | cut -f1 -d':'`; do\
        execname=`basename $$file .c`;\
        objs="$${file/%.c/.o}";\
        for header in `$(CC) $(CFLAGS) -MM $$file | tr " " "\n" | grep ".h$$" | sort | uniq | tr "\n" " "`; do\
            if [ -f $${header/%.h/.c} ]; then\
                objs+=" $${header/%.h/.o}";\
            fi;\
            for obj in `grep "^$${header/%.h/.o}" Makefile.d.tmp | tr " " "\n" | grep ".h$$" | tr "\n" " "`; do\
                if [ -f $${obj/%.h/.c} ]; then\
                    objs+=" $${obj/%.h/.o}";\
                fi;\
            done;\
        done;\
        objs=`echo -n "$$objs"  | tr " " "\n" | sort | uniq | tr "\n" " "`;\
        echo "all: $$execname" >> Makefile.d.tmp;\
        echo "$$execname: $(BINDIR)/$$execname" >> Makefile.d.tmp;\
        echo "$(BINDIR)/$$execname: $$objs" >> Makefile.d.tmp;\
        echo "  @echo \"Linking $$execname\";" >> Makefile.d.tmp;\
        echo "  @\$$(CC) \$$(LDFLAGS) -o \$$@ $$objs \$$(LIBS);" >> Makefile.d.tmp;\
        echo >> Makefile.d.tmp;\
    done;\
    mv Makefile.d.tmp $@;\

あまり堅牢ではないので、気軽に改善してください。これがどのように機能するかです。ここでの考え方は、 の各 .c ファイルについて$(SRCDIR)、メイン関数 ( ) を含むファイルを探すことですgrep "main(" src/*.c。次に、ローカル インクルードごとに、その実行可能ファイルのオブジェクト リストに#include "myfile.h"追加し、上記の行を Makefile.d に書き込みます。myfile.o

編集 この新しいバージョンのスクリプトは、bin ファイルのリンクの依存関係をサポートしています。

于 2012-10-23T15:50:21.003 に答える