Trabalhando com Makefile

Discussão sobre linux para plataformas Intel x86 ou x64 (PC)

Moderadores: 51, guest2003, Renie, gpenga

Trabalhando com Makefile

Mensagempor joao » 11 Dez 2008 13:19

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
Avatar do usuário
joao
Byte
 
Mensagens: 463
Registrado em: 17 Out 2006 08:21

Mensagempor msamsoniuk » 11 Dez 2008 20:00

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!
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor joao » 12 Dez 2008 06:10

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
Avatar do usuário
joao
Byte
 
Mensagens: 463
Registrado em: 17 Out 2006 08:21

Mensagempor msamsoniuk » 13 Dez 2008 01:00

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.
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor joao » 13 Dez 2008 15:19

Entendi...

valeu!

[]'s
Avatar do usuário
joao
Byte
 
Mensagens: 463
Registrado em: 17 Out 2006 08:21

Mensagempor joao » 18 Dez 2008 06:07

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
Avatar do usuário
joao
Byte
 
Mensagens: 463
Registrado em: 17 Out 2006 08:21

Mensagempor polesapart » 18 Dez 2008 10:02

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
Avatar do usuário
polesapart
Byte
 
Mensagens: 477
Registrado em: 19 Nov 2007 12:56
Localização: Curitiba

Mensagempor joao » 18 Dez 2008 10:35

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
Avatar do usuário
joao
Byte
 
Mensagens: 463
Registrado em: 17 Out 2006 08:21

Mensagempor msamsoniuk » 18 Dez 2008 13:38

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.
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor polesapart » 18 Dez 2008 13:52

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.
Avatar do usuário
polesapart
Byte
 
Mensagens: 477
Registrado em: 19 Nov 2007 12:56
Localização: Curitiba

Mensagempor joao » 29 Jan 2009 07:22

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
Avatar do usuário
joao
Byte
 
Mensagens: 463
Registrado em: 17 Out 2006 08:21

Mensagempor polesapart » 29 Jan 2009 09:35

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
Avatar do usuário
polesapart
Byte
 
Mensagens: 477
Registrado em: 19 Nov 2007 12:56
Localização: Curitiba

Mensagempor joao » 29 Jan 2009 09:44

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
Avatar do usuário
joao
Byte
 
Mensagens: 463
Registrado em: 17 Out 2006 08:21

Mensagempor polesapart » 29 Jan 2009 09:54

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...
Avatar do usuário
polesapart
Byte
 
Mensagens: 477
Registrado em: 19 Nov 2007 12:56
Localização: Curitiba

Mensagempor joao » 30 Jan 2009 07:01

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
Avatar do usuário
joao
Byte
 
Mensagens: 463
Registrado em: 17 Out 2006 08:21

Próximo

Voltar para Linux ( x86 ou x64 )

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 0 visitantes

x