PsySc0rpi0n Posted August 7, 2013 at 09:56 PM Report #521155 Posted August 7, 2013 at 09:56 PM (edited) Boas... Tenho estado a ler o artigo do pwseo que com todo o mérito foi escolhido para artigo de capa da 37ª edição da Revista a Programar aqui do site mas estou com algumas dúvidas. Na página 9 da revista, o artigo tem o seguinte code: SOURCES := $(wildcards *.c) OBJECTS := $(patsubst %.c, %.o, $(SOURCES)) Depois na explicação deste código, diz que todos os files .c serão substituídos por ficheiros .o preservando o texto representado por %. Então é como que se renomeássemos os files .c para files .o? Não estou a perceber o que se pretende aqui. Se os files .c forem substituídos por files .o, ficamos sem os files .c para alterarmos mais tarde se houver necessidade. Edited August 7, 2013 at 11:00 PM by PsySc0rpi0n Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
pwseo Posted August 7, 2013 at 10:42 PM Report #521162 Posted August 7, 2013 at 10:42 PM (edited) PsySc0rpi0n, A substituição é feita na lista de nomes contida na variável SOURCES, ou seja, não há alteração do nome de ficheiro nenhum no disco. No entanto, é criada uma nova lista (chamada OBJECTS) cujo conteúdo é igual à lista SOURCES mas com todas as terminações .c substituídas por .o. Resumindo: não acontece nada aos ficheiros. Apenas pegamos numa lista de nomes terminados em .c e fazemos, a partir dela, uma lista com os mesmos nomes, mas terminados em .o. Edited August 7, 2013 at 11:24 PM by pwseo
PsySc0rpi0n Posted August 8, 2013 at 08:32 AM Author Report #521182 Posted August 8, 2013 at 08:32 AM Na página 11, o que o comando sed faz é escrever num ficheiro o que ele lá tem à frente, certo? E aquilo é RegEx não é? Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
pwseo Posted August 8, 2013 at 09:09 AM Report #521184 Posted August 8, 2013 at 09:09 AM O comando sed recebe texto do gcc e altera-o. Posteriormente, esse texto é guardado num ficheiro com a extensão .d. Na revista, ainda na página 11, tens um exemplo do output do gcc antes e depois de ser alterado pelo sed. E sim, é regex. Mas o sed por si só não escreve nada para ficheiro nenhum... isso é feito graças ao operador de redireccionamento >, que obriga a que o output seja escrito no ficheiro representado pela variável $@.
PsySc0rpi0n Posted August 13, 2013 at 11:19 AM Author Report #521596 Posted August 13, 2013 at 11:19 AM (edited) Ok...Olha estou a ver pela net uns tutos sobre Regex e sobre o sed e só ainda não vi o que significa o parte da expressão. Vou aqui dizer o que entendi a ver se está certo. 1 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Comando substituir, usando o separador !. 2 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Encontrar no início da linha o caracter '('. 3 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Aqui não sei bem o significado do '.' e não sei se o '\+' é o caractere '+' ou se tem outro significado. 4 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Encontrar o caracter ')'. 5 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Encontrar os caracteres '.o:' 6 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Caractere de separação. 7 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Variável DEPDIR seguida da barra '/' 8 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Aqui também não sei. Só conheço o 'd' que é para apagar. Não sei se é para representar o caractere '1' seguido de '.d' ou se é para considerar '\1' uma parte e o '.o:' outra parte diferente. 9 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Variável OBJDIR seguida da barra '/'. 10 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Aqui é a mesma dúvida que em 8. 11 - sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Mesmo que em 6. sed 's!^\(.\+\).o: !$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@' Enviar resultado para a variável $@ que é o nome do alvo... Edited August 13, 2013 at 11:41 AM by PsySc0rpi0n Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
HappyHippyHippo Posted August 13, 2013 at 11:37 AM Report #521599 Posted August 13, 2013 at 11:37 AM https://qualysguard.qualys.com/qwebhelp/fo_help/module_pc/policies/regular_expression_symbols.htm ! exclamation point Do not match the next character or regular expression. IRC : sim, é algo que ainda existe >> #p@p Portugol Plus
PsySc0rpi0n Posted August 13, 2013 at 11:44 AM Author Report #521600 Posted August 13, 2013 at 11:44 AM (edited) Entretanto eu editei a mensagem e agora fiquei naquela... O '!' pertence ao sed ou à expressão regular? É que o caractere a seguir ao 's' representa o caractere de separação a usar... Estive a ver aqui. http://www.tutorialspoint.com/unix/unix-regular-expressions.htm Não consegui colocar o link na palavra "aqui". Quando clico em "Guardar Alterações" o link desaparece! Edited August 13, 2013 at 11:57 AM by PsySc0rpi0n Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
pwseo Posted August 13, 2013 at 11:47 AM Report #521602 Posted August 13, 2013 at 11:47 AM (edited) Ao contrário do referido no link o HappyHippyHippo encontrou, o ponto de exclamação não tem significado nenhum nas expressões regulares, e neste caso específico nem sequer faz parte da expressão mas sim do comando passado ao sed: 's!padrao!substituição!'. Por uma questão de hábito e conveniência, eu utilizo ! em vez de / nos comandos do sed (e do vim): 's!a!b!' é o mesmo que 's/a/b/' e que 's#a#b#' e que 's|a|b|', etc. Mas Psysc0rpi0n, eu disse especificamente que essa parte fugia do âmbito do artigo, o que significa que foge do âmbito dos Makefiles propriamente ditos... Se te meteres agora a aprender a usar o sed, amanhã irás desviar-te para outro programa, depois de amanhã para ainda outro, e quando deres por ti, já saíste completamente do domínio dos Makefiles. Tens que saber focar-te numa tarefa. Edited August 13, 2013 at 11:51 AM by pwseo
PsySc0rpi0n Posted August 13, 2013 at 11:54 AM Author Report #521604 Posted August 13, 2013 at 11:54 AM Sim, eu li pwseo. Tens razão, mas é suposto eu saber construir Makefiles sem saber o que está neste parte do How To??? Ao colocar essa "expressão" a coisa funciona sempre? Eu penso que não porque também deve depender de como tenho a estrutura de directórios, ou não? Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
pwseo Posted August 13, 2013 at 12:14 PM Report #521609 Posted August 13, 2013 at 12:14 PM (edited) O tutorial é sobre Makefiles, e sim, é suposto conseguires construí-los sem saber utilizar o sed. Aliás, muitos dos meus makefiles não utilizam o sed porque dizem respeito a pequenos projectos nos quais eu mesmo acrescento as dependências manualmente. Para o tutorial, o que interessa é que o sed converte o texto main.o em deps/main.d obj/main.o. Para compreender o tutorial é só isto que precisamos de saber acerca da função do sed. Mais que isso, foge ao âmbito do tutorial e, mais ainda, foge ao âmbito desta thread. Claro que ninguém te impede de aprenderes como funcionam as expressões regulares ou o sed (aliás, eu encorajo todos os programadores a fazerem isso mesmo!), mas não é suposto, num texto sobre makefiles (ou uma thread), estarmos a discutir a fundo um programa auxiliar. De qualquer das formas, aqui fica uma breve explicação do comando: Sempre que vês $(variavel), isso significa que esse texto vai ser substituído pelo valor da variável em questão. Esta substituição é feita pelo make, o que significa que o sed nunca vai ler "$(variavel)" em lado nenhum, mas sim o seu valor. Os comandos \( e \) servem para criar um grupo. Nalguns motores de regex, podemos usar os parêntesis directamente sem barras, mas por defeito o sed exige as barras. Para que queremos criar grupos? para podermos utilizá-los mais tarde, com \1, \2, etc (pela ordem em que são criados). O ponto final significa "qualquer carácter", e o código \+ (o sed exige a colocação da barra, por defeito) significa "um ou mais do especificado anteriormente": um ou mais de qualquer carácter, portanto. O sed verá então o seguinte comando: s!^\(.\+\).o:!deps/\1.d obj/\1.o:! Isso fará com que ele isole o nome do ficheiro procure por um nome qualquer seguido de ".o", isola esse nome num grupo (o grupo 1, portanto), e substitui tudo isso por "deps/\1.d obj/\1.o", substituindo \1 pelo nome isolado anteriormente. A parte que diz "> $@" não diz respeito ao sed nem ao make mas sim à shell, e indica que o output do sed deverá ser escrito no ficheiro representado por $@ (que varia consoante a regra em execução). Em caso de mais dúvidas, sugiro que cries um tópico na secção apropriada, porque um tópico sobre Makefiles não pode incluir uma discussão detalhada sobre coisas que lhe são alheias... Edited August 13, 2013 at 03:52 PM by pwseo
PsySc0rpi0n Posted August 13, 2013 at 04:45 PM Author Report #521630 Posted August 13, 2013 at 04:45 PM Ok, pwseo... Bem, eu tentei seguir o How To mas não consegui fazer o Makefile... Os meus programas, claro que não precisam de Makefiles nem tão pouco de vários files. Mas eu quero começar a saber como repartir com lógica os programas, sejam pequenos ou grandes. E quero também aprender a fazer os Makefiles... Então, neste momento eu tenho apenas duas pastas, src e include. Dentro de cada pasta tenho 3 e 2 ficheiros respectivamente. O Makefile está assim: CC := gcc 6 CFLAGS := -Wall -Werror -Wextra -pedantic -std=c99 -lm 7 8 BINDIR := ./bin/ 9 OBJDIR := ./obj/ 10 SRCDIR := ./src/ 11 DEPDIR := ./depends/ 12 13 SOURCES := $(wildcard $(SRCDIR)*.c) 14 OBJECTS := $(patsubst $(SRCDIR)%.c, $(OBJDIR)%.o, $(SOURCES)) 15 DEPENDS := $(patsubst $(SRCDIR)%.c, $(DEPDIR)%.d, $(SOURCES)) 16 17 $(BINDIR)datastore: $(OBJECTS) | $(BINDIR) 18 @echo "Linking $@" 19 @$(CC) -o $@ $^ 20 21 $(OBJDIR)%.o: $(SRCDIR)%.c | $(OBJDIR) 22 @echo "Compiling $*.c" 23 @(CC) $(CFLAGS) -c -o $@ $< 24 25 $(BINDIR) $(OBJDIR): 26 @mkdir $@ 27 28 uninstall: 29 @rm -f $(BINDIR)* 30 @rm -f $(OBJDIR)* 31 .PHONY: uninstall Ao fazer make, dá o seguinte erro: Compiling fileman.c /bin/sh: 1: Syntax error: word unexpected make: ** [obj/fileman.o] Erro 2 Não sei ao que se refere o erro 2 nem qual é a "word unexpected"... Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
PsySc0rpi0n Posted August 13, 2013 at 05:44 PM Author Report #521638 Posted August 13, 2013 at 05:44 PM Estive a ver agora que nem compilando directamente, está a dar. Tenho a seguinte estrutura: DataStore/include DataStore/src include/main.h include/menus.h src/main.c src/fileman.c src/listman.c Estou a tentar compilar assim dentro da directoria DataStore: gcc -c -o obj/main.o src/main.c mas dá o seguinte erro: src/main.c:1:26: fatal error: include/main.h: Arquivo ou diretório não encontrado compilation terminated. Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
pwseo Posted August 13, 2013 at 05:53 PM Report #521641 Posted August 13, 2013 at 05:53 PM Uma vez que estás a utilizar uma directoria de "includes" tens que adaptar o teu Makefile para a incluir no comando de compilação, passando a flag -Idir ao gcc (substituis dir pela directoria dos includes). Omiti esta questão do tutorial porque para pequenos programas não é necessária esta separação de ficheiros .c e .h (e fundamentalmente, não quis complicar ainda mais as relações de dependências). Quanto ao outro erro do "word unexpected", falta-te o cifrão antes de (CC) na regra que compila os ficheiros .c para .o
PsySc0rpi0n Posted August 13, 2013 at 06:59 PM Author Report #521647 Posted August 13, 2013 at 06:59 PM Então qual a diferença do DEPENDS e DEPDIR para o -Idir??? Pensei que esta parte do DEPDIR e DEPENDS era para os includes... Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
pwseo Posted August 13, 2013 at 07:07 PM Report #521648 Posted August 13, 2013 at 07:07 PM (edited) DEPENDS é uma lista de ficheiros com a extensão .d que contêm as dependências para um ficheiro de mesmo nome, mas de extensão .c. DEPDIR é a directoria onde armazenamos esses ficheiros .d. Isto é um mecanismo artificial que estruturamos para que o Makefile seja capaz de "encontrar" as dependências sozinho. Os ficheiros .h que tu tens na directoria de includes só serão encontrados pelo compilador se lhe passares a flag -Idir. Podes definir uma variável chamada INCDIR cujo valor seja a directoria dos includes e passar -I$(INCDIR) às invocações do gcc. Reconheço que o título "Como lidar com #includes?" poderá induzir as pessoas em erro, mas isso só acontece se tentarem compilar um projecto com uma directoria separada para os includes, como no teu caso. E se estão a tentar isso, então já deveriam estar a par da flag -I, caso contrário nunca conseguiram compilar um projecto semelhante manualmente (e antes de usarmos o make, convém que saibamos utilizar manualmente o compilador que pretendemos automatizar). Edited August 13, 2013 at 07:09 PM by pwseo
PsySc0rpi0n Posted August 13, 2013 at 09:05 PM Author Report #521655 Posted August 13, 2013 at 09:05 PM Mas é tipo file1.c depende de file2.c... Estes tratam-se com o DEPENDS e DEPDIR e os .h é com o include, é isso? Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
pwseo Posted August 13, 2013 at 09:09 PM Report #521656 Posted August 13, 2013 at 09:09 PM É mais ou menos isso, sim.
PsySc0rpi0n Posted August 13, 2013 at 10:29 PM Author Report #521666 Posted August 13, 2013 at 10:29 PM Há outra coisa que não percebi. A ordem pela qual os comandos estão escritos, tem importância, certo? Então e o comando/regra para criar as pastas vem depois das que criam as listas de objectos e dependências e etc? E também antes do comando/regra que gera o binário? Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
pwseo Posted August 13, 2013 at 10:31 PM Report #521667 Posted August 13, 2013 at 10:31 PM Não, a ordem das regras não tem importância, excepto para determinar qual é a regra pré-definida (que é a primeira).
PsySc0rpi0n Posted August 13, 2013 at 11:22 PM Author Report #521671 Posted August 13, 2013 at 11:22 PM (edited) Ok... Mas continuo sem conseguir fazer a coisa... Tenho mais perguntas... 1 - Quando temos mais que um source file (.c) temos que usar o DEPDIR e o DEPENDS, certo? 2 - A flag -I. indica para procurar na actual directoria '.' por files .h, certo? 3- Se tenho files .h na directoria include/, a flag passa a ser -I.include/, certo? 4 - A variável $(TARGET) não precisa de ser definida, pois não? O que tem ela e onde vai buscar o seu conteúdo? 5 - A mesma questão para $(LFLAGS) 6 - Explicar o $(@D) em @mkdir -p $(@D)... As duas últimas questões vêm de um Makefile que estou a ver que não é da minha autoria... Estava só a tentar entender... PS: A acção de "linking" não é a criação dos files .o a partir dos files .c? E a compilação não é a criação dos executáveis a partir dos .c ou dos .o caso existam? Edited August 13, 2013 at 11:30 PM by PsySc0rpi0n Kurt Cobain - Grunge misses you Nissan GT-R - beast killer
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now