InglêsFrancêsEspanhol

Ad


favicon do OnWorks

makepp_cookbook - On-line na nuvem

Execute makepp_cookbook no provedor de hospedagem gratuita OnWorks no Ubuntu Online, Fedora Online, emulador online do Windows ou emulador online do MAC OS

Este é o comando makepp_cookbook que pode ser executado no provedor de hospedagem gratuita OnWorks usando uma de nossas múltiplas estações de trabalho online gratuitas, como Ubuntu Online, Fedora Online, emulador online de Windows ou emulador online de MAC OS.

PROGRAMA:

NOME


makepp_cookbook – A melhor maneira de configurar makefiles para diversas situações

DESCRIÇÃO


Descobri que praticamente ninguém lê o manual de uma ferramenta de fabricação, porque francamente
ninguém está realmente interessado no processo de fabricação em si – estamos interessados ​​apenas nos resultados.
Portanto, este livro de receitas foi elaborado na esperança de que as pessoas consigam o que precisam
rapidamente a partir dos exemplos sem percorrer o manual. Isso mostra como digitar
perguntas, enquanto as instruções de instalação e os obstáculos serão encontrados no
perguntas frequentes.

Prédio bibliotecas
Do Você clientes necessidade a biblioteca?

Tenho visto vários programas grandes que consistem em um grande número de módulos, cada um deles
que reside em seu próprio diretório. Normalmente, cada diretório é colocado em sua própria biblioteca,
e então o programa final é vinculado a todas as bibliotecas.

Em muitos casos, acho que em vez de usar uma biblioteca, existe uma abordagem melhor. Bibliotecas
não são realmente a solução certa se cada módulo não puder ou não for reutilizado em qualquer outro
programa, porque então você terá todas as desvantagens das bibliotecas e nenhuma das
vantagens. As bibliotecas são úteis nos seguintes casos:

1. Quando você tem um monte de sub-rotinas que precisam ser vinculadas a vários
programas, e nenhum programa realmente usa 100% das sub-rotinas - cada programa usa um
subconjunto diferente. Neste caso, provavelmente é uma boa ideia usar uma biblioteca estática (um
.a arquivo ou um arquivo compactado).

2. Quando você tem um módulo que deve ser vinculado a vários programas diferentes e você
deseja carregá-lo dinamicamente para que cada programa não precise ter uma cópia separada do
a biblioteca. Bibliotecas dinâmicas podem economizar espaço em arquivos executáveis ​​e, às vezes, melhorar
desempenho do sistema porque há apenas uma cópia da biblioteca carregada para todos os
diferentes programas que o utilizam.

3. Quando o tempo de link é proibitivamente longo, usar bibliotecas compartilhadas para grandes partes de
o programa pode acelerar significativamente o link.

O uso de bibliotecas estáticas tem uma desvantagem principal: em alguns sistemas (por exemplo, Linux), a ordem
no qual você vincula as bibliotecas é extremamente importante. O vinculador processa bibliotecas
na ordem especificada em sua linha de comando. Ele pega tudo o que acha que precisa
cada biblioteca e depois passa para a próxima biblioteca. Se alguma biblioteca subsequente se referir a um
símbolo que ainda não foi incorporado de uma biblioteca anterior, o vinculador não
saiba voltar e pegá-lo da biblioteca anterior. Como resultado, pode ser necessário
para listar a biblioteca várias vezes na linha de comando do vinculador. (trabalhei em um projeto
onde tivemos que repetir toda a lista de bibliotecas três vezes. Este projeto é o que fez
prefiro a abordagem alternativa sugerida abaixo, a da vinculação incremental.)

O uso de bibliotecas dinâmicas tem várias desvantagens. Primeiro, seu programa pode ser ligeiramente
mais lento para iniciar se a biblioteca ainda não estiver sendo usada por algum outro programa, porque
ele deve ser encontrado e carregado. Em segundo lugar, pode ser um verdadeiro incômodo obter toda a dinâmica
bibliotecas instaladas nos locais corretos; você não pode simplesmente copiar o executável do programa,
você também deve certificar-se de copiar todas as suas bibliotecas. Terceiro, em alguns sistemas,
é difícil depurar código dentro de bibliotecas compartilhadas porque os depuradores não suportam
eles bem.

Se o seu módulo nunca for usado em nenhum outro programa, então há poucos motivos para usar
uma biblioteca: você obtém todas as desvantagens de usar bibliotecas e nenhuma das vantagens.
A técnica que prefiro é usar vinculação incremental, onde estiver disponível.

Aqui está como você pode fazer isso no Linux:

meu_módulo.o : $(filter_out meu_module.o, $(curinga *.o))
ld -r -o $(saída) $(entradas)

O que isso fará é criar outro .o arquivo chamado meu_módulo.o, que consistirá em
todo o .o arquivos neste subdiretório. O vinculador resolverá tantos dos
referências que puder, e deixará as referências restantes para serem resolvidas em um
fase subseqüente de vinculação. No nível superior, quando você finalmente cria seu programa,
em vez de vincular com libmy_module.a or libmy_module.so, você simplesmente vincularia com
meu_módulo.o. Quando você vincula .o arquivos, você não terá problemas com dependência de ordem no
linha de comando do vinculador.

Deixando makepp descobrir Fora qual biblioteca módulos e guarante que os mesmos estão necessário

Mesmo se você tiver uma biblioteca verdadeira, onde um determinado programa precisa apenas de alguns arquivos dele
(em vez de cada módulo), o makepp pode ser capaz de descobrir quais módulos são
necessários da biblioteca e inclua apenas aqueles na compilação. Isso pode salvar a compilação
tempo se você estiver desenvolvendo a biblioteca junto com um programa, porque você não se preocupa em
compile módulos de biblioteca que não são necessários para o programa específico em que você está trabalhando.

Se sua biblioteca observar estritamente a convenção de que todas as funções ou classes declaradas em
um arquivo xyz.h são completamente implementados em um arquivo fonte que compila para xyz.o (ou seja, você
não divida a implementação em xyz1.o e xyz2.o), então você pode usar o
Função "$(infer_objects)" para dizer ao makepp para extrair apenas os módulos relevantes do
biblioteca. Isso pode funcionar surpreendentemente bem para bibliotecas com dezenas de arquivos incluídos.
Basicamente, "$(infer_objects)" examina a lista de .h arquivos incluídos e parece
para correspondente .o arquivos. Se você estiver desenvolvendo rapidamente uma biblioteca e um programa
juntos, isso pode economizar tempo de compilação, porque você nunca se preocupa em compilar módulos de
a biblioteca que o programa não usa.

Aqui está um exemplo de como eu o uso:

meu_programa: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(entradas) -o $(saída) $(SYSTEM_LIBRARIES)

A função "$(infer_objects )" retorna seu primeiro argumento (após fazer curinga
expansão nele) e também procura na lista de arquivos em seu segundo argumento, por
arquivos cujo nome é igual ao nome de qualquer .h arquivos incluídos por qualquer arquivo em seu primeiro
argumento. Se algum desses arquivos for encontrado, ele será adicionado à lista.

Prédio a estático biblioteca

Se você tem certeza de que realmente precisa de uma biblioteca e a vinculação incremental não está disponível ou
não é o que você deseja fazer, existem algumas maneiras de fazer isso. Primeiro, aqui está um exemplo
onde todos os arquivos estão listados explicitamente:

LIBRARY_FILES=abcde

libmine.a: $(LIBRARY_FILES).o
& rm -f $ (saída)
$ (AR) cr $ (saída) $ (entradas)
ranlib $(output) # Pode não ser necessário, dependendo do seu sistema operacional.

O &rm é o comando "rm" integrado do makepp. Se você está acostumado a escrever makefiles, você pode estar
um pouco surpreso com este comando; você pode estar acostumado com algo mais parecido com isto:

libmine.a: $(LIBRARY_FILES).o
$(AR)ru $@ $? # Não recomendado!!!!!!!
ranlib $(saída)

onde $? (também conhecido como "$(changed_inputs)") é uma variável automática que significa quaisquer arquivos
que mudaram desde a última vez que a biblioteca foi construída, e $@ é praticamente o mesmo
como "$(saída)".

Esta abordagem não é recomendada por vários motivos:

· Suponha que você remova um arquivo fonte do diretório atual. Ainda está no
biblioteca, porque você não reconstruiu a biblioteca do zero. Como resultado, qualquer coisa
que os links com esta biblioteca terão o obsoleto .o arquivo, e isso pode estragar o seu
constrói. (Certa vez, fiquei completamente confuso com isso quando estava tentando remover código morto
de um projeto: continuei excluindo arquivos e eles ainda estavam vinculados, então pensei que o código estava
morto. No entanto, quando outra pessoa reconstruiu o projeto do zero, não vinculou nenhum
mais! O problema era que o antigo .o os arquivos ainda estavam no arquivo.)

Além disso, dependendo de suas opções para "ar" e de sua implementação de "ar" (por exemplo, se você
usar a opção "q" em vez de "r"), você pode acabar tendo várias versões do
mesmo .o no interior da .a arquivo. Se as diferentes versões definirem globais diferentes, o
o vinculador pode tentar extrair os dois. Isso provavelmente é uma coisa ruim.

É por isso que primeiro removemos o arquivo da biblioteca e o criamos do zero. Isso vai
demora um pouco mais do que apenas atualizar módulos em uma biblioteca, mas não muito mais; sobre
um computador moderno, a quantidade de tempo consumido pelo ar programa é minúsculo comparado
ao que o compilador C ocupa em uma compilação típica, então não vale a pena se preocupar
sobre.

· Uma das maneiras pelas quais o makepp tenta garantir compilações corretas é que ele irá
reconstruir automaticamente se a linha de comando para construir um determinado destino tiver sido alterada. Mas
usando o $? variável pode causar problemas, porque cada vez que a biblioteca é atualizada,
o comando build é diferente. (Você pode suprimir isso usando
":build_check ignore_action"; veja makepp_build_check para detalhes.)

· Atualizar o arquivo em vez de reconstruí-lo tornará impossível para o makepp
coloque o arquivo corretamente em um cache de construção (veja makepp_build_cache para detalhes).

Às vezes você pode achar que listar todos os arquivos é um pouco chato, especialmente se um
O projeto está em rápido desenvolvimento e a lista de arquivos está em constante mudança. Isto
pode ser mais fácil construir a biblioteca usando curingas, como este:

libmine.a: $(only_targets *.o)
& rm $ (saída)
$ (AR) cr $ (saída) $ (entradas)

Isto coloca todos os .o arquivos no diretório atual para a biblioteca. O curinga
combina com qualquer .o arquivo que existe ou pode ser construído, então funcionará mesmo que os arquivos não
ainda existe.

A função "only_targets" é usada para excluir .o arquivos que não possuem correspondência
arquivos de origem mais. Suponha que você tenha um arquivo chamado xyz.c que você costumava colocar em seu
biblioteca. Isto significa que há um xyz.o arquivo por aí. Agora você exclui xyz.c
porque está obsoleto, mas você esquece de deletar xyz.o. Sem os "only_targets"
função, xyz.o ainda estaria incluído na lista de .o arquivos incluídos na biblioteca.

Prédio a dinâmico biblioteca

O processo de construção de bibliotecas dinâmicas depende inteiramente do sistema. eu altamente
recomendo usar libtool para construir uma biblioteca dinâmica (veja
<http://www.gnu.org/software/libtool/>), então você não precisa descobrir como fazer isso
sua plataforma, e para que seu makefile continue funcionando mesmo quando você mudar para um
sistema operacional diferente. Veja a documentação da libtool para detalhes. Aqui está um exemplo de Makefile:

LIBTOOL :=libtool

libflick.la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(entradas) -o $(saída)

%.lo: %.c
$(LIBTOOL) --mode=compilar $(CC) $(CFLAGS) $(INCLUDES) -c $(entrada) -o $(saída)

Prédio on vários diferente máquinas or redes
Um dos problemas mais irritantes com makefiles é que eles quase nunca funcionam quando você
mudar para uma máquina diferente ou para uma rede diferente. Se seus makefiles tiverem que funcionar
todas as máquinas possíveis do planeta, então você provavelmente precisará de algum tipo de configuração
roteiro. Mas se você só tiver que trabalhar em algumas máquinas diferentes, há diversas maneiras
você pode abordar este problema:

Use a diferente incluir lima in todos os que o ambientes

No início de cada makefile, você pode incluir uma linha como esta:

incluir system_defs.mk

O arquivo sistema_defs.mk normalmente estariam localizados em um local diferente para cada
ambiente. Se você deseja que seus diretórios de construção sejam idênticos em todas as máquinas, coloque
sistema_defs.mk em um diretório acima dos diretórios de construção, ou então forneça um caminho de inclusão
para makepp usando a opção de linha de comando "-I".

Isso geralmente é um pouco doloroso de fazer, mas funciona bem se houver um grande número de
diferenças.

Use if declarações

Esta é a maneira mais feia de fazer isso, mas geralmente funciona.

ifsys i386
CC := gcc
senão ifsys sun4u
CC:=cc
senão ifsys hpux11
CC=c89
endif

Se tudo que você precisa fazer é encontrar alguns programas ou bibliotecas ou incluir arquivos em diferentes
lugares, pode haver maneiras melhores (veja abaixo).

encontrar_programa, primeiro_disponível, achar arquivo

Essas funções podem pesquisar vários diretórios diferentes em seu sistema para encontrar o
arquivos apropriados. Isso não é tão poderoso quanto um script de configuração, é claro, mas acho
útil. Por exemplo, eu faço o seguinte:

CXX ;= $(localizar_programa g++ c++ pg++ cxx CC aCC)
# Escolha o primeiro compilador C++ disponível em PATH.
# (Aliás, se você não definir CXX, isso
# é a forma como é definido.)
TCL_INCLUDE ;= -I$(dir_noslash $(encontrar arquivo tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include\
/usr/include/tcl8.4 / usr / include / tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $(findfile ) procura tcl.h em cada um dos indicados
# diretórios e retorna o caminho completo. Isto é então
# convertido em uma opção de compilação removendo o
# nome do arquivo (saindo do diretório) e prefixando com -I.
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(entrada) -o $(saída)

TCL_LIB ;= $((primeiro_disponível
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# Descubra onde está a biblioteca Tcl. Isto é então explicitamente
# listado no comando link:
meu_programa: *.o
$(CXX) $(CXXFLAGS) $(entradas) -o $(saída) $(TCL_LIB)

Tire vantagem of Perl's configuração INFORMAÇÕES

As técnicas acima podem não ser suficientes se você precisar de alguma informação adicional sobre
seu sistema, como se existe um long double ou qual é a ordem dos bytes. No entanto,
perl já calculou essas coisas, então você pode simplesmente usar suas respostas.

O script autoconfigure do Perl disponibiliza todas as suas informações de configuração através
o hash%Config. Não há sintaxe para acessar um hash Perl diretamente no makepp, mas você pode
entre em Perl e defina variáveis ​​escalares, que são diretamente acessíveis no makepp:

perl_begin
# Busca valores do hash de configuração.
usar configuração;
$CC = $Config{'cc'}; # Compilador C que o Perl usou;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_definido = $Config{'d_longdbl'} eq 'define';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

Além disso, depois de fazer o 'use Config', você pode usar a instrução "$(perl)", como
esta:

SHARED_LIB_EXTENSION := $(perl $Config{'dlext'})

Digite "perldoc Config" para ver quais informações estão disponíveis por meio do hash%Config.

A configuração do Perl é um bom lugar para obter informações como tipos inteiros, bytes
ordem e outras coisas que geralmente requerem um script de configuração separado para serem localizadas. Alguns
suas informações relacionadas à presença de coisas no sistema de arquivos podem não ser
válido. Por exemplo, $Config{'cc'} refere-se ao compilador C com o qual o perl foi construído,
que pode não ser o mesmo compilador C que você deseja usar. Na verdade, pode nem existir
no seu sistema, já que você provavelmente instalou o Perl através de um pacote binário.

Tips para utilização curingas
Correspondente todos os arquivos exceto a certo subconjunto

Os curingas do Makepp não têm como combinar todos os arquivos no momento exceto um certo
definido, mas você pode fazer isso com uma combinação de funções.

Por exemplo, suponha que você tenha um programa de teste para cada módulo de uma biblioteca, mas não
deseja incluir os programas de teste na biblioteca. Se todos os programas de teste começarem com
teste, então você pode excluí-los assim:

libprodução.a: $(filter_out test*, $(wildcard *.o))

As funções "$(filter )" e "$(filter_out )" são um conjunto muito poderoso de filtros para fazer
todos os tipos de operações de interseção e diferença de conjuntos. Por exemplo,

SUBDIRS ;= $(filter_out *test* *$(ARCH)*, $(shell find . -type d -print))
# Retorna todos os subdiretórios que não possuem
# "test" ou $(ARCH) neles.

$(filtro $(patsubst test_dir/test_%.o, %.o, $(curinga test_dir/*.o)), \
$(curinga *.o))
# Retorna uma lista de arquivos .o no atual
# diretório para o qual existe um correspondente
# arquivo test_*.o no subdiretório test_dir.
$(filter_out $(patsubst man/man3/%.3, %.o, $(curinga man/man3/*.3)), \
$(curinga *.o))
# Retorna uma lista de arquivos .o no atual
# diretório para o qual não existe uma página de manual
# com o mesmo nome de arquivo no subdiretório man/man3.

utilização que o "$(apenas_targets )" função para eliminado obsoleto .o arquivos

Suponha que você esteja construindo um programa ou biblioteca com um comando de construção como este:

programa: *.o
$ (CC) $ (entradas) -o $ (saída)

Suponha que você agora exclua um arquivo de origem. Se você esquecer de excluir o correspondente .o arquivo,
ele ainda estará vinculado, mesmo que não haja mais como construí-lo. No
futuro, o makepp provavelmente reconhecerá esta situação automaticamente e a excluirá de
a lista de caracteres curinga, mas no momento você precisa instruí-lo para excluí-lo manualmente:

programa: $(only_targets *.o)
$ (CC) $ (entradas) -o $ (saídas)

Makepp não conhece nenhuma maneira de construir o obsoleto .o arquivo mais, já que seu arquivo de origem é
desapareceu, então a função "$(only_targets)" irá excluí-lo da lista de dependências.

Tips para múltiplo diretórios
Uma das principais razões para escrever o makepp foi simplificar o manuseio de múltiplos
diretórios. Makepp é capaz de combinar comandos de construção de vários makefiles, para que possa
lidar corretamente com uma regra em um makefile que depende de um arquivo que é construído por um
makefile diferente.

O Quê para do in lugar of recursiva fazer

Makepp suporta make recursivo para compatibilidade com versões anteriores, mas é altamente recomendado
Que Você não use-o. Se você não sabe o que é, ótimo.

Consulte "Melhor sistema para compilações hierárquicas" no makepp para obter detalhes sobre por que você não deseja
use make recursivo ou pesquise na web por "make recursivo considerado prejudicial".

Em vez de fazer um make recursivo para tornar o alvo "all" em cada makefile, é
geralmente é mais fácil deixar o makepp descobrir quais alvos realmente precisarão ser construídos.
Além disso, se você colocar todos os seus .o e arquivos de biblioteca no mesmo diretório que o
makefiles, então o makepp descobrirá automaticamente quais makefiles são necessários também - o
a única coisa que é necessária é que seu nível superior liste os arquivos necessários
para a etapa final de vinculação. Veja os exemplos abaixo.

completa makefile para cada diretório: com implicitamente carregamento

A maneira mais comum de lidar com vários diretórios é colocar um makefile em cada diretório
que descreve como construir tudo dentro ou a partir desse diretório. Se você colocar .o arquivos em
no mesmo diretório dos arquivos de origem e, em seguida, carregamento implícito (consulte "Carregamento implícito" em
makepp_build_algorithm) encontrará automaticamente todos os makefiles. Se você colocar o seu .o
arquivos em um diretório diferente (por exemplo, em um subdiretório dependente de arquitetura), então você
provavelmente terá que carregar todos os makefiles relevantes usando a instrução "load_makefile".

Aqui está um exemplo de makefile de nível superior para uma hierarquia de diretórios que usa carregamento implícito
para construir um programa que consiste em muitas bibliotecas compartilhadas (mas veja "Você realmente precisa de um
biblioteca?" em makepp_cookbook, porque criar um programa a partir de um monte de bibliotecas compartilhadas
não é necessariamente uma boa ideia):

# Makefile de nível superior:
programa: main.o **/*.la # Link em bibliotecas compartilhadas de todos os subdiretórios.
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(entradas) -o $(saída) $(LIBS)

Isso é praticamente tudo que você precisa no makefile de nível superior. Em cada subdiretório, você
provavelmente faria algo assim:

# Makefile em cada subdiretório:
include standard_defs.mk # Pesquisas ., .., ../ .., etc. até que
# encontra o arquivo de inclusão indicado.
# substitua algumas definições de variáveis ​​aqui
SPECIAL_FLAGS := -do_something_diferente

Cada makefile provavelmente pode ser praticamente o mesmo se os comandos para construir os alvos
são bastante semelhantes.

Finalmente, você colocaria o seguinte no standard_defs.mk arquivo (que provavelmente deveria
estar localizado no diretório de nível superior):

# Configurações de variáveis ​​comuns e regras de construção para todos os diretórios.
CFLAGS: = -g -O2
INCLUDE_DIR := $(find_upwards inclui)
# Pesquisas ., .., ../ .., etc. para um arquivo ou
# diretório chamado inclui, então se você colocar
# todos os seus arquivos incluídos lá, isso irá
# encontrá-los.
INCLUI := -I$(INCLUDE_DIR)

%.lo: %.c
$(LIBTOOL) --mode=compilar $(CC) $(CFLAGS) $(INCLUDES) -c $(entrada) -o $(saída)

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(saída) $(entradas)
# $(relative_to ., ..) retorna o nome do atual
# subdiretório relativo ao nível superior
# subdiretório. Então, se este makefile for xyz/Makefile,
# esta regra irá construir xyz/libxyz.la.

# Publique arquivos de inclusão públicos no diretório de inclusão de nível superior:
$(INCLUDE_DIR)/public_%.h : público_%.h
:build_check símbolo
& ln -fr $ (entrada) $ (saída)

completa makefile para cada diretório: explícito carregamento

Se você quiser colocar todos os seus .o arquivos em um subdiretório dependente da arquitetura, então
o exemplo acima deve ser modificado para algo assim:

# Makefile de nível superior:
MAKEFILES := $(wildcard **/Makeppfile) # Lista de todos os subdiretórios para
# obtém makefiles de.

load_makefile $(MAKEFILES) # Carrega todos eles.

include standard_defs.mk # Obtenha o comando de compilação para main.o.

programa: $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(entradas) -o $(saída) $(LIBS)
# */**/$(ARCH) exclui o subdiretório
# $(ARCH), onde não queremos construir
# uma biblioteca compartilhada.

Cada makefile seria exatamente igual a antes:

# Makefile em cada subdiretório:
incluir standard_defs.mk
# ... substituições de variáveis ​​aqui

E, finalmente, standard_defs.mk conteria algo como o seguinte:

# Configurações de variáveis ​​comuns e regras de construção para todos os diretórios.
ARCH; = $ (shell uname -s) - $ (shell uname -m) - $ (shell uname -r)
# Às vezes as pessoas usam apenas $ (shell uname -m), mas
# isso será o mesmo para FreeBSD e Linux em
# um x86. O -r não é realmente útil no Linux,
# mas é importante para outros sistemas operacionais: binários para
# O SunOS 5.8 normalmente não funciona no SunOS 5.7.
&mkdir -p $(ARCH) # Verifique se o diretório de saída existe.
CFLAGS: = -g -O2
INCLUDE_DIR := $(find_upwards inclui)
# Pesquisas ., .., ../ .., etc. para um arquivo ou
# diretório chamado inclui, então se você colocar
# todos os seus arquivos incluídos lá, isso irá
# encontrá-los.
INCLUI := -I$(INCLUDE_DIR)

$(ARCH)/%.lo : %.c
$(LIBTOOL) --mode=compilar $(CC) $(CFLAGS) $(INCLUDES) -c $(entrada) -o $(saída)

$(ARCO)/ lib$(relative_to., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(saída) $(entradas)
# $(relative_to ., ..) retorna o nome do atual
# subdiretório relativo ao nível superior
# subdiretório. Então, se este makefile for xyz/Makefile,
# esta regra irá construir xyz/$(ARCH)/libxyz.la.

# Copie os arquivos de inclusão públicos para o diretório de inclusão de nível superior:
$(INCLUDE_DIR)/public_%.h : público_%.h
& cp $ (entrada) $ (saída)

Automaticamente fazer que o arquivos criados

Se todos os seus makefiles forem extremamente semelhantes (como no exemplo acima), você pode dizer ao Makepp
para construí-los automaticamente se eles não existirem. Basta adicionar o seguinte ao seu nível superior
arquivo make:

SUBDIRS := $(filter_out indesejado_dir1 indesejado_dir2, $(curinga */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "incluir standard_defs.mk" -o $(saída)
&echo "_include adicional_defs.mk" -o >>$(saída)
# Se o arquivo adicional_defs.mk existir, então
# será incluído, mas se não existir,
# a instrução _include será ignorada.

Agora os próprios makefiles serão construídos automaticamente.

completa makefile at que o topo nível

Se todos os seus makefiles forem idênticos, você pode perguntar: por que eu deveria ter um makefile em cada
nível? Por que não colocar tudo isso no makefile de nível superior?

Sim, isso pode ser feito. A principal desvantagem é que fica mais difícil especificar
diferentes opções de construção para cada subdiretório. Uma segunda desvantagem é que o seu
makefile provavelmente ficará um pouco mais difícil de ler.

Aqui está um exemplo de como fazer exatamente isso:

# Makefile de nível superior para hierarquia de diretórios. Constrói o programa
# de um conjunto de bibliotecas compartilhadas como exemplo. (Veja as advertências acima
# para saber por que você pode querer usar links incrementais ou algum outro
# abordagem em vez de bibliotecas compartilhadas.)
makepp_percent_subdirs := 1 # Permite que % corresponda a vários diretórios.
SUBDIRS := $(filter_out *CVS* other-inwanted_dirs $(wildcard **))
CFLAGS: = -g -O2
INCLUI := -Iinclui

%.lo: %.c
$(LIBTOOL) --mode=compilar $(CC) $(INCLUDES) $(CFLAGS) -c $(entrada) -o $(saída)

$ (foreach)/ lib$(notdir $(foreach)).la: $(foreach)/*.lo : foreach $(SUBDIRS)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(saída) $(entradas)
#Regra para fazer todas as bibliotecas.

programa: main.o **/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(saída) $(entradas)

inclui/$(notdir $(foreach)): $(foreach): foreach **/public_*.h
& cp $ (entrada) $ (saída)
# Exemplo de regra para copiar publicamente
# arquivos .h acessíveis no lugar certo.

A limpar alvo

Makefiles tradicionais contêm um alvo limpo, que permite remover tudo o que foi
construído. Existem três razões pelas quais você não deve fazer isso com o makepp:

1. Makepp faz de tudo para garantir uma construção correta. Então o desesperado "eu não
sei o que há de errado", fazer você querer começar do zero é coisa do passado.

2. Às vezes, as pessoas tentam economizar tempo fazendo duas coisas contraditórias ao mesmo tempo:
"fazer tudo limpo". Isto pode confundir o sistema curinga inteligente do makepp, porque irá
primeiro obtenha os fatos antes de fazer qualquer coisa. Depois vem a ação limpa, que faz
não diga ao makepp o que ele faz (na verdade, não pode, porque desfaz alguma coisa - o
ao contrário da finalidade de uma ferramenta de construção). Depois vem "todos", menos os arquivos atualizados,
que onde estavam, desapareceram misteriosamente.

3. Existe o comando “makeppclean”, que faz a mesma coisa e com mais eficiência.

No entanto, mantemos esta seção histórica, pois ela diz algo sobre o
maneira como o makepp funciona: um alvo falso chamado "clean" é apenas um nome para um conjunto de comandos para
remova todos os arquivos resultantes do processo make. Normalmente, um alvo limpo parece
algo assim:

$ (falso limpo):
&rm -fm $(curinga *.o .makepp_log)
# -m e .makepp_log eliminam todo o lixo do makepp.

Em vez de listar explicitamente os arquivos que deseja excluir, você também pode dizer ao makepp para
remova tudo que ele sabe construir, assim:

$ (falso limpo):
&rm -fm .makepp_log $(only_targets *)

Isto tem a vantagem de que se algum dos seus arquivos de origem puder ser compilado a partir de outros arquivos,
eles também serão excluídos; por outro lado, obsoleto .o arquivos (arquivos que costumavam ser
buildable, mas cujo arquivo de origem foi removido) não será excluído.

Se você tiver uma compilação que envolva makefiles em vários diretórios diferentes, seu principal
makefile de nível pode fazer referência ao alvo "limpo" (ou qualquer outro alvo falso) em um diferente
arquivo make:

# Makefile de nível superior
SUBDIRS := sub1 sub2

# crie regras aqui

# Limpe após a construção:
$(falso limpo): $(SUBDIRS)/limpo
&rm -fm .makepp_log $(only_targets *)

Alternativamente, você pode colocar seu alvo "limpo" apenas no makefile de nível superior e tê-lo
processe todos os diretórios, assim:

$ (falso limpo):
&rm -fm $(apenas_targets **/*)

utilização Qt's potência pré-processador
Este exemplo mostra um makefile para um utilitário que usa a biblioteca Qt GUI da Nokia (veja
<http://qt.nokia.com>). A única coisa um pouco incomum nisso é que você
deve executar um pré-processador chamado "moc" na maioria dos arquivos ".h" que contêm definições de widget,
mas você não deseja executar "moc" em nenhum arquivo ".h" que não use a macro "Q_OBJECT".

Automaticamente determinando qual arquivos necessidade potência arquivos

Você poderia, é claro, apenas listar todos os arquivos ".h" que precisam ter o "moc" executado neles.
Entretanto, se você estiver desenvolvendo rapidamente novos widgets, pode ser um incômodo
continue atualizando a lista no makefile. Você pode contornar a necessidade de listar o moc
módulos explicitamente com algo assim:

MOC := $(QTDIR)/bin/moc
MÓDULOS := quaisquer módulos que você tenha em seu programa
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# Verifica todos os arquivos .h em busca da macro Q_OBJECT.

meu_programa: $(MÓDULOS).o $(MOC_MODULES).o
$ (CXX) $ (entradas) -o $ (saída)

moc_%.cxx: %.h # Cria os arquivos moc a partir dos arquivos .h.
$ (MOC) $ (entrada) -o $ (saída)

% .o:% .cxx
$ (CXX) $ (CXXFLAGS) -c $ (entrada) -o $ (saída)

Essa abordagem examina cada um dos seus .h arquivos toda vez que o makepp é executado, procurando pelo
Macro "Q_OBJETO". Parece caro, mas provavelmente não demorará muito. (O .h
todos os arquivos terão que ser carregados do disco de qualquer maneira pelo processo de compilação, então eles serão
ser armazenado em cache.)

#include que o .moc lima

Outra abordagem é "#incluir" a saída do pré-processador "moc" no seu widget
arquivo de implementação. Isso significa que você deve se lembrar de escrever o "#include", mas ele tem
a vantagem de que há menos módulos para compilar e, portanto, a compilação é mais rápida.
(Para a maioria das compilações C++, a maior parte do tempo é gasta lendo os arquivos de cabeçalho e
a saída do pré-processador precisa incluir quase tantos arquivos quanto o seu widget
de qualquer maneira.) Por exemplo:

// meu_widget.h
classe MeuWidget: public QWidget {
Q_OBJETO
// ...
}

// meu_widget.cpp

#include "meu_widget.h"
#include "my_widget.moc" // my_widget.moc é a saída do
// pré-processador moc.
// Outras coisas de implementação aqui.
MyWidget::MyWidget(QWidget * pai, const char * nome):
QWidget(pai, nome)
{
// ...
}

Agora você precisa ter uma regra no seu makefile para fazer todos os arquivos “.moc”, assim:

MOC := $(QTDIR)/bin/moc
# Regra para criar arquivos .moc:
%.moc: %.h
$ (MOC) $ (entrada) -o $ (saída)

Makepp é inteligente o suficiente para perceber que precisa criar "my_widget.moc" se isso não acontecer
já existe ou se está desatualizado.

Esta segunda abordagem é a que costumo usar porque acelera a compilação.

Replacements para obsoleta fazer expressões idiomáticas
FAZER OBJETIVOS

Às vezes as pessoas têm regras em seu makefile que dependem do alvo que estão construindo,
usando a variável especial "MAKECMDGOALS". Por exemplo, às vezes vemos coisas como
esta:

ifneq ($(produção de filtro, $(MAKECMDGOALS)),)
CFLAGS: = -O2
outro
CFLAGS: = -g
endif

Isso funcionará bem com makepp. No entanto, recomendo não usar "MAKECMDGOALS" para tais
casos (e o mesmo acontece com o manual de criação do GNU). É melhor você colocar seu otimizado e
compilado por depuração .o arquivos em diretórios separados, ou dando-lhes diferentes prefixos ou
sufixos, ou usando repositórios, para mantê-los separados.

Provavelmente, o único momento em que você realmente deseja fazer referência a "MAKECMDGOALS" é se
leva muito tempo para carregar seus makefiles e você não precisa disso para seu alvo "limpo"
(mas você não precisa de um alvo limpo). Por exemplo,

ifneq ($(MAKECMDGOALS),limpo)
load_makefile $(curinga **/Makeppfile)
outro
no_implicit_load . # Impede o carregamento automático de quaisquer outros makefiles.
endif

$ (falso limpo):
&rm -f $(curinga **/*.o)

Recursivo fazer para construir in diferente diretórios

Consulte "Dicas para vários diretórios" em makepp_cookbook.

Recursivo fazer para alterar valor of a variável

Alguns makefiles se reinvocam com um valor diferente de uma variável, por exemplo, o debug
alvo no seguinte fragmento makefile

.PHONY: tudo depurado

otimizado:
Programa $(MAKE) CFLAGS=-O2

depurar:
$(MAKE) programa CFLAGS=-g

programa: ao bo
$(CC) $(CFLAGS) $^ -o $@

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

Se o usuário digitar "make debug", ele criará o programa no modo padrão com a depuração habilitada
em vez de com otimização.

A melhor maneira de fazer isso é construir dois programas diferentes, com dois conjuntos diferentes de
arquivos objeto, assim:

CFLAGS: = -O2
DEBUG_FLAGS := -g
MÓDULOS := ab

programa: $(MÓDULOS).o
$ (CC) $ (CFLAGS) $ (entradas) -o $ (saída)

depurar/programa: depurar/$(MÓDULOS).o
$(CC) $(DEBUG_FLAGS) $(entradas) -o $(saída)

% .o:% .c
$ (CC) $ (CFLAGS) -c $ (entrada) -o $ (saída)

depuração/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(entrada) -o $(saída)

$(depuração falsa): depuração/programa

A vantagem de fazer desta forma é (a) você não precisa reconstruir tudo quando você
mude de depuração para otimizado e vice-versa; (b)

O texto acima pode ser escrito de forma um pouco mais concisa usando repositórios. A seguir
makefile é exatamente equivalente:

depuração do repositório=. # Faz com que o subdiretório debug pareça uma cópia do
# o subdiretório atual.
load_makefile depurar CFLAGS=-g
# Substitui CFLAGS quando invocado no subdiretório de depuração
CFLAGS := -O2 # Valor de CFLAGS quando invocado neste subdiretório

programa: ao bo
$(CC) $(CFLAGS) $^ -o $@

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

$(depuração falsa): depuração/programa
# Se o usuário digitar "makepp debug", compila
# depurar/programar em vez de programa.

Gerais dicas
Como funciona o dobrador de carta de canal do I construir um parte diferentemente apenas por uma vez?

Makepp torna isso difícil porque o resultado é inconsistente com as regras.
Mas há situações em que você pode precisar disso, por exemplo, para compilar apenas um módulo com
informações de depuração pesadas. Você pode conseguir isso em duas etapas, primeiro construindo o
dependência separadamente e, em seguida, excluindo-a da fase de link:

makepp DEBUG=3 buggy.o # Construa com outra opção.
makepp --dont-build=buggy.o buggy # Use-o, apesar da opção de compilação "errada".

Como funciona o dobrador de carta de canal do I fazer certo my saída diretórios existir?

Você pode especificar uma regra para construir o diretório de saída e, em seguida, certificar-se de que cada arquivo que
vai no diretório de saída depende disso. Mas geralmente é mais fácil fazer algo como
esta:

# A maneira clássica
manequim := $(teste de shell -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# Isso geralmente é mais fácil do que fazer com que todos os arquivos dependam
# $(OUTPUT_DIRECTORY) e ter uma regra para fazer isso.
# Observe que você deve usar := em vez de = para forçar
# execute imediatamente.
# Uma abordagem alternativa: usando código Perl, OUTPUT_DIRECTORY local var
perl_begin
-d $OUTPUT_DIRECTORY ou mkdir $OUTPUT_DIRECTORY;
perl_end
# A maneira moderna, não faz nada pelos diretórios existentes
&mkdir -p $(OUTPUT_DIRECTORY)

Uma dessas instruções deve estar próxima ao topo do seu makefile, para que sejam executadas
antes de qualquer coisa que possa precisar do diretório.

Como funciona o dobrador de carta de canal do I força a comando para executar on cada construir?

A maneira mais fácil é não usar o mecanismo de regras, mas simplesmente executá-lo, como
esta:

fictício := $(data do shell > last_build_timestamp)

Ou coloque-o em um bloco perl, assim:

perl_begin
system("comando para executar");
perl_end

Esta abordagem tem a desvantagem de ser executada mesmo que um alvo não relacionado seja
sendo executado.

Uma segunda abordagem é declarar o arquivo como um alvo falso, mesmo que seja um arquivo real.
Isso forçará o makepp a reexecutar o comando para construí-lo todas as vezes, mas somente se
aparece na lista de dependências de alguma regra.

Como funciona o dobrador de carta de canal do I encurtar que o exibido construir comandos?

Muitas vezes há tantas opções para comandos de compilação que o que é exibido no
a tela está ilegível. Você pode alterar o que é exibido suprimindo a exibição do
comando inteiro e, em seguida, imprima explicitamente a parte interessante do comando. Isso é
fácil imprimir apenas a parte relevante do comando usando "$(filter_out)", como
esta:

ALL_CFLAGS = $(CFLAGS) $(INCLUDES) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

% .o:% .c
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(entrada)
@$(CC) $(ALL_CFLAGS) -c $(entrada) -o $(saída)

(O "@" na frente do comando suprime a impressão do comando.)

Isso permitirá que você veja a maioria das opções interessantes, mas não exibirá todas as
incluem diretórios (dos quais geralmente existem muitos!). Se a parte que você está interessado
in é contíguo em seu comando, você também pode usar a função "print" (que adiciona um
nova linha, então você não quer vários deles):

alvo:
@... $(imprimir parte interessante) ...

Como funciona o dobrador de carta de canal do I converter a lima para dentro dependências?

Para alguns formatos de arquivo obscuros não vale a pena implementar um scanner. Em um projeto
temos arquivos xml, digamos foobar.xml que contém as dependências para foobar.out:


a
b
c


Decidimos aderir a este layout simples, por isso não precisamos analisar o xml. Com o
builtin &sed, aqui está o que fazemos com três substituições simples para os três tipos de
linhas:

%.d: %.xml
&sed's! !$(stem).out: \\! || e! (.+) !$$1 \\! || e! !# Vazio!' \
$(entrada) -o $(saída)

incluir foobar.d

A tentativa de incluir isso produz primeiro "foobar.d":

foobar.out: \
uma \
b \
c\
# Vazio

A linha vazia (apenas um comentário ou realmente vazia) evita ter que se preocupar com o final
barra invertida. Uma alternativa para produzir uma lista multilinha é:

%.d: %.xml
&sed's! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g'\
$(entrada) -o $(saída)

incluir foobar.d

Isso produz um equivalente:

foobar.out: $((
a
b
c
))

Se você tiver uma reescrita mais complexa para fazer, defina uma função dentro do makefile ou em um
módulo que você inclui. Por exemplo, $_ indefinido irá pular as linhas de entrada:

sub meufiltro {
retornar undef $_ se /
meu $stem = f_stem;
e! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed's! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g'\
$(entrada) -o $(saída)

incluir foobar.d

Use makepp_cookbook online usando serviços onworks.net


Servidores e estações de trabalho gratuitos

Baixar aplicativos Windows e Linux

Comandos Linux

Ad