我正在构建一个带有一些最简单设施的简单库。然而,make抱怨在构建unitest时存在未定义的引用。我已经发布了所有代码和makefile。这是什么原因?
文件层次结构:
/bin
/build
Makefile
/src
dbg.h
ex30.c
libex30.c
/tests
dbg.h
libex30_tests.c
minuint.h
runtests.sh
生成文件:
CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
LIBS=-ldl $(OPTLIBS)
PREFIX?=/usr/local
SOURCES=$(wildcard src/**/*.c src/*.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))
TARGET=build/libYOUR_LIBRARY.a
#SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
# The Target Build
#all: $(TARGET) $(SO_TARGET) tests
all: $(TARGET) tests
dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: all
$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
ar rcs $@ $(OBJECTS)
ranlib $@
#$(SO_TARGET): $(TARGET) $(OBJECTS)
# $(CC) -shared -o $@ $(OBJECTS)
build:
@mkdir -p build
@mkdir -p bin
# The Unit Tests
.PHONY: tests
tests: CFLAGS += $(TARGET)
tests: $(TESTS)
sh ./tests/runtests.sh
valgrind:
VALGRIND="valgrind --log-file=/tmp/valgrind-%p.log" $(MAKE)
# The Cleaner
clean:
rm -rf build $(OBJECTS) $(TESTS)
rm -f tests/tests.log
find . -name "*.gc*" -exec rm {} \;
rm -rf `find . -name "*.dSYM" -print`
# The Install
install: all
install -d $(DESTDIR)/$(PREFIX)/lib/
install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/
# The Checker
BADFUNCS='[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)'
check:
@echo Files with potentially dangerous functions.
@egrep $(BADFUNCS) $(SOURCES) || true
在/ src目录中,我有两个文件ex30.c,libex30.c和dbg.h
ex30.c:
#include <stdio.h>
#include "dbg.h"
#include <dlfcn.h>
typedef int (*lib_function)(const char *data);
int main(int argc, char *argv[])
{
int rc = 0;
check(argc == 4, "USAGE: ex30 libex30.so function data");
char *lib_file = argv[1];
char *func_to_run = argv[2];
char *data = argv[3];
void *lib = dlopen(lib_file, RTLD_NOW);
check(lib != NULL, "Failed to open the library %s: %s", lib_file, dlerror());
lib_function func = dlsym(lib, func_to_run);
check(func != NULL, "Did not find %s function in the library %s: %s", func_to_run, lib_file, dlerror());
rc = func(data);
check(rc == 0, "Function %s return %d for data: %s", func_to_run, rc, data);
rc = dlclose(lib);
check(rc == 0, "Failed to close %s", lib_file);
return 0;
error:
return 1;
}
libex30.c:
#include <stdio.h>
#include <ctype.h>
#include "dbg.h"
int print_a_message(const char *msg)
{
printf("A STRING: %s\n", msg);
return 0;
}
int uppercase(const char *msg)
{
int i = 0;
// BUG: \0 termination problems
for(i = 0; msg[i] != '\0'; i++) {
printf("%c", toupper(msg[i]));
}
printf("\n");
return 0;
}
int lowercase(const char *msg)
{
int i = 0;
// BUG: \0 termination problems
for(i = 0; msg[i] != '\0'; i++) {
printf("%c", tolower(msg[i]));
}
printf("\n");
return 0;
}
int fail_on_purpose(const char *msg)
{
return 1;
}
dbg.h:
#ifndef __dbg_h__
#define __dbg_h__
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef NDEBUG
#define debug(M, ...)
#else
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d:%s: " M "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#endif
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define check(A, M, ...) if(!(A)) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
#define sentinel(M, ...) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
#define check_mem(A) check((A), "Out of memory.")
#define check_debug(A, M, ...) if(!(A)){debug(M, ##__VA_ARGS__); errno=0; goto error;}
#endif
在/ tests中,我有libex30_tests.c,minunit.h和dbg.h:
libex30_tests.c:
#include "minunit.h"
char *test_dlopen()
{
return NULL;
}
char *test_functions()
{
return NULL;
}
char *test_failures()
{
return NULL;
}
char *test_dlclose()
{
return NULL;
}
char *all_tests() {
mu_suite_start();
mu_run_test(test_dlopen);
mu_run_test(test_functions);
mu_run_test(test_failures);
mu_run_test(test_dlclose);
return NULL;
}
RUN_TESTS(all_tests);
minunit.h
#undef NDEBUG
#ifndef _minunit_h
#define _minunit_h
#include <stdio.h>
#include "dbg.h"
#include <stdlib.h>
#define mu_suite_start() char *message = NULL
#define mu_assert(test, message) if (!(test)) { log_err(message); return message; }
#define mu_run_test(test) debug("\n-----%s", " " #test); \
message = test(); tests_run++; if (message) return message;
#define RUN_TESTS(name) int main(int argc, char *argv[]) {\
argc = 1; \
debug("----- RUNNING: %s", argv[0]);\
printf("----\nRUNNING: %s\n", argv[0]);\
char *result = name();\
if (result != 0) {\
printf("FAILED: %s\n", result);\
}\
else {\
printf("ALL TESTS PASSED\n");\
}\
printf("Tests run: %d\n", tests_run);\
exit(result != 0);\
}
int tests_run;
#endif
runtests.sh:
echo "Running unit tests:"
for i in tests/*_tests
do
if test -f $i
then
if $VALGRIND ./$i 2>> tests/tests.log
then
echo $i PASS
else
echo "ERROR in test $i: here's tests/tests.log"
echo "------"
tail tests/tests.log
exit 1
fi
fi
done
echo ""
这是我在制作之后得到的:
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG build/libYOUR_LIBRARY.a tests/libex30_tests.c -o tests/libex30_tests
In file included from tests/libex30_tests.c:1:0:
tests/libex30_tests.c: In function ‘main’:
tests/minunit.h:15:38: warning: parameter ‘argc’ set but not used [-Wunused-but-set-parameter]
#define RUN_TESTS(name) int main(int argc, char *argv[]) {\
^
tests/libex30_tests.c:38:1: note: in expansion of macro ‘RUN_TESTS’
RUN_TESTS(all_tests);
^
/tmp/ccqde9jD.o: In function `main':
/home/rex/rex/projects/programming/c/learn_hard_way/ex30/tests/libex30_tests.c:38: multiple definition of `main'
build/libYOUR_LIBRARY.a(ex30.o):/home/rex/rex/projects/programming/c/learn_hard_way/ex30/src/ex30.c:9: first defined here
build/libYOUR_LIBRARY.a(ex30.o): In function `main':
ex30.c:(.text.startup+0x85): undefined reference to `dlopen'
ex30.c:(.text.startup+0x9c): undefined reference to `dlsym'
ex30.c:(.text.startup+0x120): undefined reference to `dlclose'
ex30.c:(.text.startup+0x188): undefined reference to `dlerror'
ex30.c:(.text.startup+0x1f0): undefined reference to `dlerror'
collect2: error: ld returned 1 exit status
make: *** [tests/libex30_tests] Error 1
答案 0 :(得分:2)
这些符号由-ldl
导出。与{{1}}链接。
答案 1 :(得分:0)
您应该在Makefile sg中添加一条规则,如下所示:
%: %.c ${OTHER_OBJECTS_AND_ARCHIVES}
${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} -o $@ $^ ${LIBS}
答案 2 :(得分:0)
您的Makefile
中存在多个问题。而且,我不得不猜测一下正确的文件层次结构。而且,您的list.c
不完整
Makefile
中的一个大问题就是您用来构建测试的这一行:
tests: CFLAGS += $(TARGET)
$(TARGET)
是您的图书馆.a
文件。通过这种方式指定命令,无论何时构建测试,您都会得到一个命令(例如):
cc -o mytest1 -O2 -g lib.a mytest1.c
问题是{<1}}在编译 lib.a
之前会检测依赖关系,因此mytest1.c
想要来自mytest1.c
的符号是<链接器知道em> not ,因此没有从库中提取任何内容。
正确的命令是:
lib.a
要在cc -o mytest1 -O2 -g mytest1.c lib.a
中正确指定,请参阅以下更改。
我修复了你的Makefile
并注释了上述错误以及其他一些错误:
Makefile
提醒:由于代码块在SO上的发布方式,makefile中的标签会转换为空格。因此,当您拉动makefile时,您需要将一行中的前导空格转换为单个选项卡。否则,您会看到(例如)可怕的# NOTE/BUG: there are issues with _not_ using full path. they _can_ be solved
# without doing this, but this makes things easier
SRC := $(shell pwd)
# NOTE: to just _build_ the tests but _not_ try to run them, specify:
# RUNTESTS=tests
# on the command line
RUNTESTS ?= runtests
# NOTE: cosmetic change to library name
###LIBNAME = YOUR_LIBRARY
LIBNAME = lcthw
CFLAGS += -g
CFLAGS += -O2
CFLAGS += -Wall
# NOTE: IMO, -Wextra is overkill and causes more problems than it's worth
# what I do is something like this and then do:
# make CMDLINE_CFLAGS=-Wextra
# on those rare occasions where it might be useful
###CFLAGS += -Wextra
CFLAGS += $(CMDLINE_CFLAGS)
CFLAGS += -I$(SRC) -rdynamic -DNDEBUG $(OPTFLAGS)
LIBS=-ldl $(OPTLIBS)
PREFIX?=/usr/local
# library sources and objects
# NOTE/BUG: the wildcard was failing
###SOURCES=$(wildcard src/**/*.c src/*.c)
SOURCES=$(wildcard lcthw/*.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
# test sources and objects
TEST_SRC=$(wildcard tests/*_tests.c)
TEST_OBJS=$(patsubst %.c,%.o,$(TEST_SRC))
TESTS=$(patsubst %.o,%,$(TEST_OBJS))
# library target
TARGET=build/lib$(LIBNAME).a
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
TARGETS += $(TARGET)
# NOTE: comment the following out to _not_ build the shared library -- it's
# _not_ used but will be built now (to use it, change TARGET to SO_TARGET when
# building TESTS)
TARGETS += $(SO_TARGET)
# The Target Build
all: $(TARGETS) $(RUNTESTS)
###dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: CFLAGS=-g -Wall -I$(SRC) -Wall -Wextra $(OPTFLAGS)
dev: all
$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
ar rcs $@ $(OBJECTS)
ranlib $@
$(SO_TARGET): $(TARGET) $(OBJECTS)
$(CC) -shared -o $@ $(OBJECTS)
build:
@mkdir -p build
@mkdir -p bin
# The Unit Tests
# NOTE/BUG: in order to link properly $(TARGET) must be the last part of the
# command
#
# (i.e.) doing CFLAGS += $(TARGET) produced the equivalent of:
# $(CC) -o $@ $(CFLAGS) $(TARGET) $@.c
#
# instead of:
# $(CC) -o $@ $(CFLAGS) $@.c $(TARGET)
#
# the reason the first method failed was because the library was scanned
# _before_ the .c was compiled, so it didn't know to pull any .o files from
# it
#
# the second example _will_ work and is closer to what you originally specified,
# but my personal preference is to always build the .o files:
$(TESTS):
$(CC) -c $(CFLAGS) -o $@.o $@.c
$(CC) -o $@ $(CFLAGS) $@.o $(TARGET)
# just build the tests
.PHONY: tests
tests: $(TESTS)
# build and run the tests
.PHONY: runtests
runtests: $(TESTS)
sh ./tests/runtests.sh
valgrind:
VALGRIND="valgrind --log-file=/tmp/valgrind-%p.log" $(MAKE)
# The Cleaner
clean:
rm -f *.o
rm -rf bin build $(OBJECTS) $(TESTS)
rm -f $(TEST_OBJS)
rm -f tests/tests.log
find . -name "*.gc*" -exec rm {} \;
rm -rf `find . -name "*.dSYM" -print`
# The Install
install: all
install -d $(DESTDIR)/$(PREFIX)/lib/
install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/
# The Checker
BADFUNCS='[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)'
check:
@echo Files with potentially dangerous functions.
@egrep $(BADFUNCS) $(SOURCES) || true
这是我最终得到的文件层次结构:
Makefile:59: *** missing separator. Stop.
makefile可以正常工作。请注意,elixir/ex30.c
elixir/lcthw/list.c
elixir/lcthw/list.h
elixir/libex30.c
elixir/Makefile
elixir/tests/dbg.h
elixir/tests/libex30_tests.c
elixir/tests/list_tests.c
elixir/tests/minunit.h
elixir/tests/runtests.sh
可能是(例如)elixir
,因为makefile现在执行/home/elixir/projects/.../mylib
但是,如果[无意中]把东西放在错误的地方,你当然可以移动它们,但你可能需要稍微调整pwd
。
此外,即使发布了Makefile
,它也是不完整的,只定义了list.c
中大约一半的函数。这个bug被主要的makefile bug掩盖了。所以,我添加了虚拟版本以获得干净的构建:
list.h
我在修复后得到的输出看起来像这样:
#include <lcthw/list.h>
//#include <lcthw/dbg.h>
List *List_create()
{
return calloc(1, sizeof(List));
}
void List_destroy(List *list)
{
LIST_FOREACH(list, first, next, cur) {
if(cur->prev) {
free(cur->prev);
}
}
free(list->last);
free(list);
}
void List_clear(List *list)
{
LIST_FOREACH(list, first, next, cur) {
free(cur->value);
}
}
void List_clear_destroy(List *list)
{
List_clear(list);
List_destroy(list);
}
void
List_push(List *list, void *value)
{
}
void *
List_pop(List *list)
{
return NULL;
}
void
List_unshift(List *list, void *value)
{
}
void *
List_shift(List *list)
{
return NULL;
}
void *
List_remove(List *list, ListNode *node)
{
return NULL;
}
<强>更新强>
我为这个错误道歉。我意识到我混合了这两个项目...在第三次更新后...我已经纠正了错误并且我已经给出了文件层次结构。你能看看更新后的帖子吗?它的文件较少,并没有真正使用链表代码。
注意输出。 成功运行非列表测试。如果您在cc -g -O2 -Wall -I/home/myhome/elixir -rdynamic -DNDEBUG -fPIC -c -o lcthw/list.o lcthw/list.c
ar rcs build/liblcthw.a lcthw/list.o
ranlib build/liblcthw.a
cc -shared -o build/liblcthw.so lcthw/list.o
cc -c -g -O2 -Wall -I/home/myhome/elixir -rdynamic -DNDEBUG -o tests/list_tests.o tests/list_tests.c
cc -o tests/list_tests -g -O2 -Wall -I/home/myhome/elixir -rdynamic -DNDEBUG tests/list_tests.o build/liblcthw.a
cc -c -g -O2 -Wall -I/home/myhome/elixir -rdynamic -DNDEBUG -o tests/libex30_tests.o tests/libex30_tests.c
cc -o tests/libex30_tests -g -O2 -Wall -I/home/myhome/elixir -rdynamic -DNDEBUG tests/libex30_tests.o build/liblcthw.a
sh ./tests/runtests.sh
Running unit tests:
----
RUNNING: ./tests/libex30_tests
ALL TESTS PASSED
Tests run: 4
tests/libex30_tests PASS
----
RUNNING: ./tests/list_tests
FAILED: Wrong last value.
Tests run: 2
ERROR in test tests/list_tests: here's tests/tests.log
------
DEBUG tests/libex30_tests.c:32:all_tests:
----- test_failures
DEBUG tests/libex30_tests.c:33:all_tests:
----- test_dlclose
DEBUG tests/list_tests.c:113:main: ----- RUNNING: ./tests/list_tests
DEBUG tests/list_tests.c:103:all_tests:
----- test_create
DEBUG tests/list_tests.c:104:all_tests:
----- test_push_pop
[ERROR] (tests/list_tests.c:32: errno: None) Wrong last value.
Makefile:96: recipe for target 'runtests' failed
make: *** [runtests] Error 1
中填写虚拟函数,列表测试也会起作用。
实际上,list.c
项目的src
子目录不是ex30
的子目录,而是使用ex30
的子目录会更清晰。
但是,我怀疑你最终想要的是什么:
elixir/common/dbg.h
elixir/common/rules.mk
elixir/ex30/ex30.c
elixir/ex30/libex30.c
elixir/ex30/Makefile
elixir/lcthw/list.c
elixir/lcthw/list.h
elixir/lcthw/Makefile
elixir/tests/libex30_tests.c
elixir/tests/list_tests.c
elixir/tests/Makefile
elixir/tests/minunit.h
elixir/tests/runtests.sh
请注意,Makefile
的大部分内容将移至rules.mk
,每个Makefile
只会移动几行。而且,您可以添加更多具有类似子层次结构的项目。
IMO,一个可能更清晰的变种是:
elixir/common/dbg.h
elixir/common/rules.mk
elixir/ex30/ex30.c
elixir/ex30/libex30.c
elixir/ex30/libex30_tests.c
elixir/ex30/Makefile
elixir/lcthw/list.c
elixir/lcthw/list.h
elixir/lcthw/list_tests.c
elixir/lcthw/Makefile
elixir/tests/Makefile
elixir/tests/minunit.h
elixir/tests/runtests.sh
可为每个项目添加src
子目录 。
与build
一起。但是,我建议build
是一个顶级目录,它有每个项目的子目录:
elixir/build/ex30/libex30_tests
elixir/build/ex30/libex30_tests.o
elixir/build/lcthw/lcthw.a
elixir/build/lcthw/list.o
elixir/build/lcthw/list_tests.o
elixir/build/lcthw/list_tests
这样做的好处是源树层次结构不与.o
,.a
和可执行文件(即)重建的东西混杂在一起。这样可以更轻松地设置git
,因为您不需要每个项目.gitignore
文件。
YMMV,但是,我已经在每个可以想象的组织中为我自己的东西做了这个,这是我经过多次试验和错误后我已经确定的那个。
如果可以,我可以相应调整并重新发布。
为了给你一个更强大的rules.mk
文件的更具体的例子,这里有一个我很多用于SO问题。
注意:这只是一个例子。它可以不自己使用,因为它依赖于几个包装脚本来运行。不要试图使用或改编它。最适合您的方法是使用原始rules.mk
作为起点,从头开始构建自己的Makefile
。
# rules/rules.mk -- ovrstk rules control
#
# options:
# GDB -- enable debug symbols
# 0 -- normal
# 1 -- use -O0 and define _USE_GDB_=1
#
# CLANG -- use clang instead of gcc
# 0 -- use gcc
# 1 -- use clang
#
# CVERBOSE -- build verbosity
# 0 -- normal
# 1 -- add -v to cc and -Wl,--verbose to ld
#
# MKVERBOSE -- makefile/rules verbosity
# 0 -- normal
# 1 -- verbose
#
# M32 -- cross-build to 32 bit mode
# 0 -- native build
# 1 -- build for i386
#
# BNC -- enable benchmarks
# 0 -- normal mode
# 1 -- enable benchmarks for function enter/exit pairs
# 2 -- add min/max
#
# XCFLAGS -- extra command line CFLAGS
# XDFLAGS -- extra command line DFLAGS
#
# DOT_I -- generate preprocessor output
# DOT_S -- generate assembler output
#
# GLIB -- added options for glib
#
# symbols:
# DFLAGS -- -D options
# CFLAGS -- compiler options
#
# PREP -- targets to execute before ALL
# ALL -- things to build (automatically uses LIBNAME/PGMTGT)
#
# LIBNAME -- library name to build (e.g. foo.a) -- can be multiple
# OLIB -- list of .o files to build LIBNAME
# OLIB-<libname> -- list of .o files to build <libname>
#
# PGMTGT -- program to build (e.g. fludger) -- can be multiple
# OLIST -- list of .o files to build PGMTGT
# OLIST-<pgmname> -- list of .o files to build <pgmname>
#
# CLEAN -- things to clean (automatically uses a bunch of stuff)
#
# NOPROTO -- do not generate prototypes
# FINLINE -- allow gcc to inline functions automatically
# WNOERROR -- inhibit -Werror
# WEXTRA -- add -Wextra
ifdef OVRPUB
ifndef SDIR
SDIR := $(shell pwd)
STAIL := $(notdir $(SDIR))
endif
ifndef GENTOP
GENTOP := $(dir $(SDIR))
endif
ifndef GENDIR
GENDIR := $(GENTOP)/$(STAIL)
endif
ifndef ODIR
ODIR := $(GENDIR)
endif
NOPROTO := 1
endif
# disable prototype generation
ifdef NOPROTO
PROTOLST := true
PROTOGEN := @true
else
PROTOLST := qproto
PROTOGEN := @qproto
PROTOALL := proto
endif
ifndef SDIR
$(error rules: SDIR not defined)
endif
ifndef ODIR
$(error rules: ODIR not defined)
endif
ifndef GENDIR
$(error rules: GENDIR not defined)
endif
ifndef GENTOP
$(error rules: GENTOP not defined)
endif
ifndef _rules_mk_
_rules_mk_ = 1
CLEAN += $(LIBNAME) $(PGMTGT)
ifndef NOPROTO
CLEAN += *.proto
endif
CLEAN += *.a
CLEAN += *.o
CLEAN += *.i
CLEAN += *.dis
CLEAN += *.lst
CLEAN += *.TMP
QPROTO := $(shell $(PROTOLST) -i -l -O$(GENTOP) $(SDIR)/*.c $(CPROTO))
HDEP += $(QPROTO)
###VPATH += $(GENDIR)
###VPATH += $(SDIR)
ifdef INCLUDE_MK
-include $(INCLUDE_MK)
endif
ifdef M32
CFLAGS += -m32
endif
ifdef CVERBOSE
CFLAGS += -v
endif
ifdef MKVERBOSE
MSG := @echo
else
MSG := @true
endif
ifdef GSYM
CFLAGS += -gdwarf-2
endif
ifdef GDB
CFLAGS += -gdwarf-2
DFLAGS += -D_USE_GDB_
else
CFLAGS += -O2
endif
ifdef DEBUG
DFLAGS += -DDEBUG=$(DEBUG)
endif
ifndef ZPRT
DFLAGS += -D_USE_ZPRT_=0
endif
ifdef BNC
DFLAGS += -D_USE_BNC_=$(BNC)
endif
ifdef GLIB
_GLIB = glib-2.0
DFLAGS += $(shell pkg-config --cflags $(_GLIB))
STDLIB += $(shell pkg-config --libs $(_GLIB))
endif
ifdef CLANG
CC := clang
CXX := clang++
else
ifdef CPLUS
ifeq ($(STDLIB),)
STDLIB += -lstdc++
endif
endif
endif
# alternate -std
# NOTE: clang++ does not understand c++17
ifdef CSTD
_CSTD := $(CSTD)
ifdef CLANG
ifdef CPLUS
ifeq ($(CSTD),c++17)
_CSTD := c++1y
endif
endif
endif
CFLAGS += -std=$(_CSTD)
endif
ifdef MPI
export PATH := /usr/lib64/openmpi/bin:$(PATH)
CC := mpicc
CXX := mpicxx
endif
DFLAGS += -I$(GENTOP)
DFLAGS += -I$(OVRTOP)
DFLAGS += -I$(OVRBNC)
CFLAGS += -Wall
ifndef WNOERROR
CFLAGS += -Werror
endif
ifdef WEXTRA
CFLAGS += -Wextra
endif
CFLAGS += -Wno-unknown-pragmas
CFLAGS += -Wempty-body
CFLAGS += -fno-diagnostics-color
ifdef DOT_I
NOLDC := @true
COPTS += -E -P
O := i
endif
ifdef DOT_S
NOLDC := @true
COPTS += -S
SOPTS += -E -P
O := s
endif
ifndef COPTS
COPTS += -c
O := o
endif
ifeq ($(O),o)
ALL += $(LIBNAME) $(PGMTGT)
else
ALL += $(addsuffix .$(O),$(basename $(PGMTGT) $(OLIST)))
endif
ifndef FINLINE
# NOTE: we now need this to prevent inlining (enabled at -O2)
ifndef CLANG
CFLAGS += -fno-inline-small-functions
endif
# NOTE: we now need this to prevent inlining (enabled at -O3)
CFLAGS += -fno-inline-functions
endif
ifdef FIXREG
ifndef CLANG
CFLAGS += $(FIXREG)
endif
endif
ifndef F95
F95 := f95
endif
ifndef LDC
ifdef FTN
LDC = $(F95)
endif
endif
ifndef LDC
ifdef CPLUS
LDC = $(CXX)
else
LDC = $(CC)
endif
endif
# FIXME/CAE -- gold wiki page says use -Wl but it seems to have no effect
ifndef CLANG
###LDC += -Wl,-fuse-ld=ld.blah
endif
ifdef CVERBOSE
LDC += -Wl,-verbose=2
endif
ifdef LIBLIST
LIBLIST := $(addprefix $(GENTOP)/,$(LIBLIST))
endif
CFLAGS += $(XCFLAGS)
DFLAGS += $(XDFLAGS)
CFLAGS += $(DFLAGS)
endif
all: $(PREP) $(PROTOALL) $(ALL)
# C
%.o: %.c $(HDEP)
$(MSG) %.o %.c
$(CC) $(CFLAGS) $(COPTS) -o $*.$(O) $<
%.i: %.c
$(MSG) %.i %.c
cpp $(DFLAGS) -P $< > $*.i
%.s: %.c
$(MSG) %.s %.c
$(CC) $(CFLAGS) -S -o $*.s $<
# C++
%.o: %.cpp $(HDEP)
$(MSG) %.o %.cpp
$(CXX) $(CFLAGS) $(COPTS) -o $*.$(O) $<
%.i: %.cpp
$(MSG) %.i %.cpp
cpp $(DFLAGS) -P $< > $*.i
%.s: %.cpp
$(MSG) %.s %.cpp
$(CXX) $(CFLAGS) -S -o $*.s $<
# asm
%.o: %.s $(HDEP)
$(MSG) %.o %.s
$(AS) $(AFLAGS) -o $*.$(O) $<
%.o: %.S $(HDEP)
$(MSG) %.o %.S
$(CC) $(CFLAGS) $(COPTS) $(SOPTS) -o $*.$(O) $<
# fortran
%.o: %.f95 $(HDEP)
$(MSG) %.o %.f95
$(F95) -c -o $*.$(O) $<
.SECONDEXPANSION:
###.SUFFIXES:
# build a library (type (2) build)
$(LIBNAME):: $(OLIB) $$(OLIB-$$@)
$(NOLDC) ar rv $@ $^
# build programs
$(PGMTGT):: $$@.o $(OLIST) $$(OLIST-$$@) $(LIBLIST)
$(NOLDC) $(LDC) $(CFLAGS) -o $@ $^ $(STDLIB)
.PHONY: proto
proto::
$(PROTOGEN) -i -v -O$(GENTOP) $(SDIR)/*.c $(CPROTO)
.PHONY: clean
clean::
rm -f $(CLEAN)
.PHONY: help
help::
egrep '^#' $(SDIR)/Makefile
以下是使用它的每个项目Makefile
:
# fastread/Makefile -- make file for fastread
#
# SO: read line by line in the most efficient way platform specific
# SO: questions/33616284
ifndef _fastread_mk_
_fastread_mk_ = 1
LIBNAME = fastread
OLIB += rdgets.o
OLIB += rdmmap.o
OLIB += lib.o
OLIB += node1.o
OLIB += node2.o
PGMTGT = xrdfile
OLIST += rdgets.o
OLIST += rdmmap.o
OLIST += lib.o
OLIST += node1.o
OLIST += node2.o
###LIBLIST = fastread/fastread.a
HDEP += fastread.h
DFLAGS += -I$(SDIR)
endif
include $(OVRTOP)/rules/rules.mk