Página 1 de 2

Trabalhando com Makefile

MensagemEnviado: 11 Dez 2008 13:19
por joao
Não achei outro lugar que poderia colocar isso, então coloquei na sessão linux mesmo.

Vejam só, gostaria de criar um makefile para usar com o wingw e linux. Até ai td bem, porque ambos serão iguais, tirando apenas os diretórios das libs e dos includes.

O que eu to tentando ver é sobre os arquivos. Como é um projeto novo, eu estou ainda colocando novos arquivos a todo momento.

E no momento está assim o meu makefile:
Código: Selecionar todos
# Project: Project1
# Compiler: Default GCC compiler
# Compiler Type: MingW 3
# Makefile created by wxDev-C++ 6.10.2 on 05/11/08 15:08

CPP       = g++.exe
CC        = gcc.exe
WINDRES   = windres.exe
OBJ       = Objects/MingW/x.o Objects/MingW/y.o Objects/MingW/z.o Objects/MingW/xx.o Objects/MingW/xy.o Objects/MingW/xz.o Objects/MingW/xx.res
LINKOBJ   = Objects/MingW/x.o Objects/MingW/y.o Objects/MingW/z.o Objects/MingW/xx.o Objects/MingW/xy.o Objects/MingW/xz.o Objects/MingW/xx.res
LIBS      = -L"C:/Program Files/Dev-Cpp/Lib" -mwindows -lwxmsw28 -lwxmsw28_gl -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregex -lwxexpat -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lwsock32 -lodbc32 -lopengl32 -lmysql  -g3
INCS      = -I"include" -I"C:/Program Files/MySQL/MySQL Server 5.0/include"
CXXINCS   = -I"C:/Program Files/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2" -I"C:/Program Files/Dev-Cpp/include" -I"C:/Program Files/Dev-Cpp/" -I"C:/Program Files/Dev-Cpp/include/common/wx/msw" -I"C:/Program Files/Dev-Cpp/include/common/wx/generic" -I"C:/Program Files/Dev-Cpp/include/common/wx/fl" -I"C:/Program Files/Dev-Cpp/include/common/wx/gizmos" -I"C:/Program Files/Dev-Cpp/include/common/wx/html" -I"C:/Program Files/Dev-Cpp/include/common/wx/mmedia" -I"C:/Program Files/Dev-Cpp/include/common/wx/net" -I"C:/Program Files/Dev-Cpp/include/common/wx/ogl" -I"C:/Program Files/Dev-Cpp/include/common/wx/plot" -I"C:/Program Files/Dev-Cpp/include/common/wx/protocol" -I"C:/Program Files/Dev-Cpp/include/common/wx/stc" -I"C:/Program Files/Dev-Cpp/include/common/wx/svg" -I"C:/Program Files/Dev-Cpp/include/common/wx/xml" -I"C:/Program Files/Dev-Cpp/include/common/wx/xrc" -I"C:/Program Files/Dev-Cpp/include/common/wx" -I"C:/Program Files/Dev-Cpp/include/common" -I"C:/Program Files/MySQL/MySQL Server 5.0/include"
RCINCS    = --include-dir "C:/PROGRA~1/Dev-Cpp/include/common"
BIN       = Output/MingW/xx.exe
DEFINES   =  -D__WXMSW__ -D__GNUWIN32__ -D__WIN95__
CXXFLAGS  = $(CXXINCS) $(DEFINES) -fno-exceptions -fno-pcc-struct-return -fstrict-aliasing -Wall -D__WXMSW__ -D__GNUWIN32__ -D__WIN95__    -fexpensive-optimizations -O3 -g3
CFLAGS    = $(INCS) $(DEFINES) -fno-exceptions -fno-pcc-struct-return -fstrict-aliasing -Wall -D__WXMSW__ -D__GNUWIN32__ -D__WIN95__   -fexpensive-optimizations -O3 -g3
GPROF     = gprof.exe
RM        = rm -f
LINK      = g++.exe

.PHONY: all all-before all-after clean clean-custom
all: all-before $(BIN) all-after

clean: clean-custom
   $(RM) $(OBJ) $(BIN)

$(BIN): $(OBJ)
   $(LINK) $(LINKOBJ) -o "Output\MingW\x.exe" $(LIBS)

Objects/MingW/x.o: $(GLOBALDEPS) x.cpp x.h
   $(CPP) -c x.cpp -o Objects/MingW/x.o $(CXXFLAGS)

Objects/MingW/y.o: $(GLOBALDEPS) y.cpp y.h
   $(CPP) -c y.cpp -o Objects/MingW/y.o $(CXXFLAGS)

Objects/MingW/z.o: $(GLOBALDEPS) z.cpp z.h
   $(CPP) -c z.cpp -o Objects/MingW/z.o $(CXXFLAGS)

Objects/MingW/xx.o: $(GLOBALDEPS) xx.cpp xx.h
   $(CPP) -c xx.cpp -o Objects/MingW/xx.o $(CXXFLAGS)

Objects/MingW/xy.o: $(GLOBALDEPS) xy.cpp xy.h
   $(CPP) -c xy.cpp -o Objects/MingW/xy.o $(CXXFLAGS)

Objects/MingW/xz.o: $(GLOBALDEPS) xz.cpp xz.h
   $(CPP) -c xz.cpp -o Objects/MingW/xz.o $(CXXFLAGS)

Objects/MingW/xx.res: Objects/MingW/xx.rc xx.rc
   $(WINDRES) --input-format=rc -o Objects/MingW/xx.res $(RCINCS) Objects/MingW/xx.RC -O coff


Desculpem, mas modifiquei o nome por não poder expo-los. Mas o resto está inteiro ai. Tanto é que se alguém quiser usar é só usar! :)

A minha pergunta é:
Tem como eu deixar ele mais dinamico? Tipo, neste momento, para adicionar um arquivo a mais, eu preciso adicionar 2 linhas novas e ainda modificar mais duas linhas(OBJ e OBJLINK). Não tem como eu deixar ele com apenas 1 linha para a inclusão do arquivo e o mesmo se encarrega de fazer o resto? Pois as linhas são muito parecidas. Mas não sei como fazer o list.

Por sinal, existe como fazer um for e um if dentro do makefile? Por exemplo, para deixar apenas 1 makefile para lin e windows, poderia modificar apenas 1 linha dizendo qual é o OS e o mesmo já se encarregava de usar a correta linha. O que acham é possível?

Obrigado,
Joao

MensagemEnviado: 11 Dez 2008 20:00
por msamsoniuk
se fizer desta forma soh precisa mexer em uma linha onde esta uma lista de modulos:

Código: Selecionar todos
TARGET = foo
MODULES = core sci app rtc ipc spi

CC      = gcc
CFLAGS  = -Wall -Iinclude
LDFLAGS = -Llib -lbar
OBJS    = $(MODULES:=.o)
DEPS    = $(MODULES:=.h)

%.o: %.c $(DEPS)
  $(CC) $(CFLAGS) -c $<

all: $(TARGET)

$(TARGET): $(OBJS)
  $(CC) $(LDFLAGS) -o $@ $(OBJS)

install: $(TARGET)
  cp $(TARGET) /tftproot

clean:
  rm -f $(TARGET) $(OBJS)


eu nao uso windows normalmente, mas as pessoas que trabalham comigo usam os mesmos makefiles no windows, sem alteracoes e mesmo sem ifs. inclusive, nao precisa colocar gcc.exe. apenas gcc funciona igual... tambem soh indico paths relativos dentro do projeto: paths do compilador estao configurados no proprio compilador.

as vezes precisa de um script mais avancado no makefile e o windows empaca... a solucao eh uma diretiva de shell

SHELL = sh

daih o makefile roda tudo!

MensagemEnviado: 12 Dez 2008 06:10
por joao
valeu!

Tava tentando entender como funciona um "vetor" no makefile.
Agora entendi como ele funciona.

Tenho outro probleminha...
Toda vez que eue mando rodar um make all, ele está compilando todos os arquivos novamente e não apenas o que eu mexi.
Sabe o porque disto?

[]'s

MensagemEnviado: 13 Dez 2008 01:00
por msamsoniuk
ele recompila verificando o que depende do que e verificando as datas... se vc usa o sistema via rede, eh necessario ter alguma coerencia de relogio na rede (via ntp ou netdate), senao nada funciona direito! :)

por exemplo, daquele makefile que eu mostrei, ele verifica como dependencia:

para fazer all, precisa testar foo. se nao tem ou tah veio, faz foo.
para fazer foo, precisa testar *.o. se nao tem ou tah veio, faz *.o
para fazer cada %.o, precisa testar %.c e DEPS (*.h). se o %.o nao existe ou tah veio, faz o %.o.
como *.o eh mais novo que foo, relinka foo e entao a dependencia all esta atendida.

um exemplo, se eu mexer em ipc.c, tenho:

root@darkstar:~/hc908rtos/0/0/6# make
sdcc -mhc08 --stack-loc 0x1BF -I. -c ipc.c
sdcc -mhc08 --stack-loc 0x1BF --code-loc 0xEE00 -o hc908rtos.S19 rtos.rel sci.rel app.rel rtc.rel stdlib.rel stdio.rel strings.rel ipc.rel
root@darkstar:~/hc908rtos/0/0/6#

que eh o que se espera, porem, se eu mexer no ipc.h, tenho:

root@darkstar:~/hc908rtos/0/0/6# make
sdcc -mhc08 --stack-loc 0x1BF -I. -c rtos.c
sdcc -mhc08 --stack-loc 0x1BF -I. -c sci.c
sdcc -mhc08 --stack-loc 0x1BF -I. -c app.c
sdcc -mhc08 --stack-loc 0x1BF -I. -c rtc.c
sdcc -mhc08 --stack-loc 0x1BF -I. -c stdlib.c
sdcc -mhc08 --stack-loc 0x1BF -I. -c stdio.c
sdcc -mhc08 --stack-loc 0x1BF -I. -c strings.c
sdcc -mhc08 --stack-loc 0x1BF -I. -c ipc.c
sdcc -mhc08 --stack-loc 0x1BF --code-loc 0xEE00 -o hc908rtos.S19 rtos.rel sci.rel app.rel rtc.rel stdlib.rel stdio.rel strings.rel ipc.rel
root@darkstar:~/hc908rtos/0/0/6#

isso ocorre pq DEPS eh uma dependencia global. poderia ter feito algo mais elaborado, porem achei que generalizar seria suficiente. normalmente o .h eh a interface logica entre os modulos e isso costuma nao mudar. por outro lado, o .c contem a implementacao interna e isso costuma mudar.

uma coisa interessante de adicionar no DEPS, alem dos .h eh o Makefile, assim qdo vc altera algo eh feito um rebuild completo.

MensagemEnviado: 13 Dez 2008 15:19
por joao
Entendi...

valeu!

[]'s

MensagemEnviado: 18 Dez 2008 06:07
por joao
Mais uma pergunta sobre o assunto:

Sei que tem como fazer um Makelist por diretorio, então, o diretório pai apenas indica o diretório filho que por sua vez tem outro makelist que tem os arquivos deste diretório e, caso tenha, tem o nome dos diretorios filhos. Resumindo, cada diretorio tem um makelist com os seus respectivos arquivos e diretorios.

Isso é bom porque vc pode fazer validações em separado para cada diretório, mas não estou conseguindo achar exemplos disso.

Alguma idéia de onde eu posso encontrar?

Obrigado,
Joao

MensagemEnviado: 18 Dez 2008 10:02
por polesapart
Tem um livro muito bom sobre o gnu make. Dá pra baixar em pdf (tem todos os capítulos).

http://oreilly.com/catalog/make3/book/index.csp

MensagemEnviado: 18 Dez 2008 10:35
por joao
Legal!

Valeu pela dica!

Estava tentando achar algum guia legal sobre isso, pois o MAN do makefile é bom, mas ainda acho que deveriam colocar mais exemplos, pois fica mais fácil de aprender...
Esse vai ajudar um monte!

Obrigado,
Joao

MensagemEnviado: 18 Dez 2008 13:38
por msamsoniuk
eh relativamente simples... no Makefile principal:

Código: Selecionar todos
all install uninstall clean:
 cd dir1 && make $@
 cd dir2 && make $@
 cd dir3 && make $@
 ...


os Makefiles secundarios sao normais, ele entra no diretorio e roda o respectivo... a logica eh que se um Makefile de diretorio parar, todos os outros param, obvio. uma desvantagem eh que ele nao resolve diretamente dependencias, ao inves disso entra em cada um deles e roda o make.

existem formas de fazer automatico, com um for, fica mais automatico, mas nao recomendo muito. essa forma eu achei mais portavel e segura.

MensagemEnviado: 18 Dez 2008 13:52
por polesapart
Esta dica eu adaptei do manual do make:


Código: Selecionar todos
SUBDIRS := include libstuff src
SUBTARGETS := all install clean distclean
PHONY += $(SUBTARGETS) $(SUBDIRS)

$(SUBTARGETS): $(SUBDIRS)
    $(MAKE) -C $@

.PHONY: $(PHONY)



Onde houver dependencias de ordem entre os diretorios (ex se voce precisa compilar libstuff antes de src, no exemplo acima), é preferível deixar isto explícito do que simplesmente listar os alvos na ordem da esquerda para a direita, na variavel SUBDIRS. O motivo é que isto nao funciona quando rodamos o make com a opcao -jX (onde X é o número de tarefas a rodar em paralelo, se voce tem uma cpu dual core é uma ótima dica passar -j2 ou até -j3).

Pra tornar as dependencias explicitas, é só escrever, por exemplo:

Código: Selecionar todos
src: libstuff


... que obriga o make a sempre tentar construir primeiro o alvo indicado no diretorio libstuff antes de tentar o src, mesmo com a opcao -j.

O bacana desta abordagem é que nao precisa do laço for, que depende do shell e não é muito portável, conforme o marcelo mencionou.

MensagemEnviado: 29 Jan 2009 07:22
por joao
Ola a todos!

Então, depois de várias dicas, tentei modificar o meu amigo Makefile do projeto e é claro que nada iria funcionar de primeira!
:D

Então vou tentar explicar aqui a vocês o que gostaria de fazer e o que está dando de errado e quem sabe vcs tem uma idéia?!?!?!?! Rezo que sim! :D

Primeiro, sei que muitos deram várias idéias legais, mas a minha idéia seria ter apenas 1 makefile(Nem vou entrar no quesito de 1 makefile para qq OS agora) central e gerar todos os objetos em um diretorio apenas. Ok?

O que tenho de estrutura de diretório é o seguinte:
Código: Selecionar todos
projeto
   |---------- Build
                |---------- build.bat
                |---------- build.sh
                |---------- build.??? (Qual que é para MAC? :) )
   |---------- Win
                |---------- ArquivoWin1.cpp
                |---------- ArquivoWin1.h
                |---------- ArquivoWin2.cpp
                |---------- ArquivoWin2.h
   |---------- Lin
                |---------- ArquivoLin1.cpp
                |---------- ArquivoLin1.h
                |---------- Arquivolin2.cpp
                |---------- ArquivoLin2.h
   |---------- Mac
                |---------- ArquivoMac1.cpp
                |---------- ArquivoMac1.h
                |---------- ArquivoMac2.cpp
                |---------- ArquivoMac1.h
   |---------- Ext_lib
                |---------- bibliotecaWin1.a
                |---------- bibliotecaWin2.a
                |---------- bibliotecaLin1.a
                |---------- bibliotecaMac1.a
   |---------- Ext_inc
                |---------- Arquivoext1.c
                |---------- Arquivoext1.h
                |---------- Arquivoext2.cpp
                |---------- Arquivoext2.h
   |---------- Arquivo1.cpp
   |---------- Arquivo1.h
   |---------- Arquivo2.cpp
   |---------- Arquivo2.h
   |---------- Arquivo3.cpp
   |---------- Arquivo3.h
   |---------- Arquivo4.cpp
   |---------- Arquivo4.h
   |---------- Arquivo5.cpp



O que eu estou fazendo é:
Código: Selecionar todos
OBJ_DIR      = Win/obj
BIN            = Win/Projeto.exe
LINK         = g++
CPP          = g++
CC           = gcc

SOURCES       = Arquivo1.cpp \
                         Arquivo2.cpp \
                               Arquivo3.cpp \
                               Arquivo4.cpp \
                               Arquivo5.cpp \
                               Win\ArquivoWin1.cpp \
                               Win\ArquivoWin2.cpp \
                               Win\ArquivoWin3.cpp \
                               projeto.res

OBJ                  =  $(subst .cpp,.o,$(SOURCES))

EXT_SOURCES   = Arquivoext1.c \
                               Arquivoext2.cpp

EXT_OBJ      =  $(subst .c,.o,$(subst .cpp,.o,$(EXT_SOURCES)))

all: $(BIN)

$(BIN): $(OBJ_DIR)/$(EXT_OBJ) $(OBJ_DIR)/$(OBJ)
       $(LINK) $(OBJ_DIR)/$(EXT_OBJ) $(OBJ_DIR)/$(OBJ) -o $(BIN) $(LIB_FLAGS)

%.o: %.c %.h
  $(CC) -o  $@ $<

%.o: %.cpp %.h
  $(CPP) -o  $@ $<

%.res: %.rc
       $(WINDRES) --input-format=rc -O coff -o $@ $(RCINCS) $<



Vcs tem idéia do que pode estar errado?
O erro que eu recebo é:
Código: Selecionar todos
C:\Temp\Projeto\Build>mingw32-make.exe -f Makefile rebuild
mingw32-make.exe: *** No rule to make target `Win/obj/Arquivoext1.c', needed by `Win/obj/Arquivoext1.o'.  Stop.


Realmente estou precisando desta ajuda, então se tiver qualquer sugestão, analisarei ela com muito agrado! :)

[]'s

MensagemEnviado: 29 Jan 2009 09:35
por polesapart
Um problema que vejo é neste tipo de regra:

%.o: %.c


Quando voce declara um objeto como:

FOO_OBJ := destdir/whatever.o

enquanto o source está em otherdir/whatever.c

a regra vai fazer a seguinte conversao:

destdir/whatever.o: destdir/whatever.c

... mas whatever.c está em outro diretorio.

Veja na documentação do make a variável VPATH, talvez quebre um galho, só não me alongo na dica por quê não está fresco na memória...

[]s

MensagemEnviado: 29 Jan 2009 09:44
por joao
Entendi o problema!

Mas infelizmente não tem como eu testar aqui...
VOu testar em casa mais tarde...

E se eu fizer isso?

$(OBJ_DIR)/%.o: %.c %.h
$(CC) -o $@ $<

Dai eu terei apenas o nome do arquivo, certo? Dai eu posso usar a dica do VPATH para resolver eu acho...

Outra coisa, sabe se ele consegue entender isso:
%.o: %.c %.h
$(CC) -o $@ $<

%.o: %.cpp %.h
$(CPP) -o $@ $<

é o mesmo começo, mas um irá usar CPP e o outro CC.

[]'s

MensagemEnviado: 29 Jan 2009 09:54
por polesapart
joao escreveu:Entendi o problema!

Mas infelizmente não tem como eu testar aqui...
VOu testar em casa mais tarde...

E se eu fizer isso?

$(OBJ_DIR)/%.o: %.c %.h
$(CC) -o $@ $<


Deve funcionar, em conjunto com o vpath.


joao escreveu:Dai eu terei apenas o nome do arquivo, certo? Dai eu posso usar a dica do VPATH para resolver eu acho...

Outra coisa, sabe se ele consegue entender isso:
%.o: %.c %.h
$(CC) -o $@ $<

%.o: %.cpp %.h
$(CPP) -o $@ $<

é o mesmo começo, mas um irá usar CPP e o outro CC.

[]'s



Sim, uso uma regra parecida aqui e vai na boa...

MensagemEnviado: 30 Jan 2009 07:01
por joao
Ola Novamente!

Então, consegui resolver em partes o problema! :D :D :D

O que acontece agora é que na hora de fazer o link é que está dando errado. Na compilação está funcionando perfeitamente:
Código: Selecionar todos
$(BIN): $(EXT_OBJ) $(OBJ)
       $(LINK)  $(OBJ_DIR)/$(EXT_OBJ)  $(OBJ_DIR)/$(OBJ)  -o $(BIN) $(LIB_FLAGS)

%.o: %.c
       $(CC) -c $< -o $(OBJ_DIR)/$@ $(INC_FLAGS)

%.o: %.cpp
       $(CPP) -c $< -o $(OBJ_DIR)/$@ $(INC_FLAGS)


O link está saindo errado:
Código: Selecionar todos
g++ Win/obj/arquivoExt1.o ArquivoExt2.o ArquivoExt3.o Win/obj/Aruivo1.o  Arquivo2.o  Arquivo3.o -o Win/Projeto.exe -L"../ext_lib/" ...


O erro é que
EXT_OBJ é: Arquivoext1.o Arquivoext2.o
OBJ é: Arquivo1.cpp Arquivo2.cpp Arquivo3.cpp

Mas quando faço o linkage:
$(OBJ_DIR)/$(EXT_OBJ) $(OBJ_DIR)/$(OBJ)

Apenas o primeiro elemento desta lista está pegando o diretório aonde estou gravando os objetos:
$(OBJ_DIR)/$(EXT_OBJ) é: Win/obj/arquivoExt1.o ArquivoExt2.o
$(OBJ_DIR)/$(OBJ) é: Win/obj/Aruivo1.o Arquivo2.o Arquivo3.o

Como posso passar para todos os elementos?

Lembrando que todos os meu objetos estão no mesmo lugar, chamado:
Projeto/Build/Win/obj/ mas como estou rodando o make dentro do Build, só estou usando Win/obj/

Mandei um monte de info para tentar o mais claro possível! :) Se não entendeu alguma parte, é só perguntar!

E obrigado pela ajuda pessoal! O link do livro eu já revirei inteiro, mas não consigo achar a solução para o meu problema nele. :(

PS: O VPATH funcionou pefeito! é só usar:
VPATH dir1 dir2 dir3
Separando eles por espaço ou :

[]'s