La construcción de mi propia biblioteca con unidades se queja de una referencia indefinida

Estoy construyendo una biblioteca simple con algunas instalaciones unitarias. Sin embargo, la marca se queja de que hay una referencia indefinida mientras se construye el unitest. He publicado todo el código y makefile. ¿Cuál es la razón para esto?

Jerarquía de archivos:

/bin /build Makefile /src dbg.h ex30.c libex30.c /tests dbg.h libex30_tests.c minuint.h runtests.sh 

Makefile:

 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 

En / src dirctory, tengo dos archivos ex30.c, libex30.c y dbg.h

ex30.c:

 #include  #include "dbg.h" #include  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  #include  #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  #include  #include  #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 

En / tests, tengo libex30_tests.c, minunit.h, y 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  #include "dbg.h" #include  #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 "" 

Esto es lo que obtengo después de hacer:

 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 

Esos símbolos son exportados por libdl.so . Enlace con -ldl .

Debes agregar una regla a tu Makefile sg como esta:

 %: %.c ${OTHER_OBJECTS_AND_ARCHIVES} ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} -o $@ $^ ${LIBS} 

Hubo varios problemas en su Makefile . Y, tuve que adivinar un poco acerca de la jerarquía de archivos correcta. Y, tu list.c estaba incompleta


El gran error en tu Makefile fue esta línea que usaste para construir tus pruebas:

 tests: CFLAGS += $(TARGET) 

$(TARGET) es su biblioteca .a archivo. Al especificar el comando de esta manera, siempre que estaba creando una prueba, recibió un comando (por ejemplo):

 cc -o mytest1 -O2 -g lib.a mytest1.c 

El problema es que lib.a se lib.a busca de dependencias antes de mytest1.c , por lo que el mytest1.c no conoce los símbolos que mytest1.c desea de lib.a por lo que el vinculador no conoce nada.

El comando correcto es:

 cc -o mytest1 -O2 -g mytest1.c lib.a 

Para especificar esto correctamente en el Makefile , vea los cambios a continuación.


He arreglado su Makefile y he anotado el error anterior, junto con algunos otros:

 # 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 # # (ie) 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 

Recordatorio: debido a la forma en que se publican los bloques de código en SO, las tabs en el archivo make se convierten en espacios. Por lo tanto, cuando tire del archivo MAKE, deberá convertir los espacios en blanco iniciales de una línea en una sola pestaña. De lo contrario, verá (por ejemplo) el temido Makefile:59: *** missing separator. Stop. Makefile:59: *** missing separator. Stop.


Aquí está la jerarquía de archivos que terminé con:

 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 

El makefile funciona correctamente contra eso. Tenga en cuenta que el elixir podría ser (por ejemplo) /home/elixir/projects/.../mylib como el archivo make ahora hace un pwd

Pero, si [inadvertidamente] pone las cosas en el lugar equivocado, puede moverlas, pero es posible que deba ajustar el Makefile un poco.


Además, a pesar de que list.c fue publicado, estaba incompleto y definió solo la mitad de las funciones en list.h Este error fue enmascarado por el error de makefile principal. Entonces, agregué versiones ficticias para obtener una comstackción limpia:

 #include  //#include  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; } 

La salida que estoy obteniendo después de las correcciones es algo como esto:

 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 

ACTUALIZAR:

Pido disculpas por el error. Me doy cuenta de que he mezclado los dos proyectos … después de actualizar la tercera vez … He corregido el error y he dado la jerarquía de archivos. ¿Podrías echar un vistazo a la publicación actualizada? Tiene menos archivos y realmente no usa el código de lista enlazada.

Observe la salida. Se ejecutaron con éxito las pruebas no listadas. Si completa las funciones ficticias en list.c , las pruebas de lista también funcionarán.

Tal como está, en lugar de un subdirectorio de src para el proyecto ex30 , sería más limpio usar un ex30 de ex30 .

Pero, lo que sospecho que realmente quieres [en última instancia] es algo como:

 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 

Tenga en cuenta que la mayor parte de Makefile se rules.mk a rules.mk y que cada Makefile sería solo unas pocas líneas. Y, puede agregar más proyectos con una sub-jerarquía similar.

En mi opinión, una variante posiblemente más limpia es:

 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 

El subdir src podría agregarse para cada proyecto.

Junto con build . Pero, lo que recomendaría para la build es un directorio de nivel superior que tiene subdirectorios por proyecto:

 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 

Esto tiene la ventaja de que la jerarquía del árbol de origen no está desordenada con .o , .a y los ejecutables (es decir,) las cosas que se reconstruyen. Esto facilita la configuración de git porque no necesita un archivo .gitignore por proyecto.

YMMV, pero, he hecho esto por mis propias cosas en cada organización concebible, y este es el único en el que me he conformado, después de mucho ensayo y error.

Si te parece bien, puedo ajustarme y volver a publicar.


Para darle un ejemplo más concreto de un archivo rules.mk más poderoso, aquí hay uno que uso mucho para las preguntas de SO.

Nota: Esto es sólo un ejemplo. No se puede usar solo porque se basa en varios scripts de envoltura para operar. No trates de usarlo o adaptarlo. La mejor ruta para usted es crear su propio rules.mk desde cero, utilizando su Makefile original como punto de partida.

 # 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 (eg foo.a) -- can be multiple # OLIB -- list of .o files to build LIBNAME # OLIB- -- list of .o files to build  # # PGMTGT -- program to build (eg fludger) -- can be multiple # OLIST -- list of .o files to build PGMTGT # OLIST- -- list of .o files to build  # # 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 

Aquí hay un Makefile por proyecto que lo usa:

 # 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