Pergunta

Eu sou um C Newb

Eu escrevo um monte de código em linguagens dinâmicas (javascript, python, Haskell, etc.), mas agora estou aprendendo C para pós-graduação e não tenho idéia do que estou fazendo.

O Problema

Inicialmente eu estava construindo toda a minha fonte em um diretório usando um makefile, que tem funcionado muito bem. No entanto, o meu projeto está crescendo e eu gostaria de dividir a fonte para vários diretórios (testes de unidade, utils, núcleo, etc.). Por exemplo, a minha árvore de diretórios pode parecer o seguinte:

.
|-- src
|   |-- foo.c
|   |-- foo.h
|   `-- main.c
`-- test
    `-- test_foo.c

test/test_foo.c usa tanto src/foo.c e src/foo.h. Usando makefiles, qual é a melhor maneira / padrão para construir este? De preferência, não haveria uma regra para a construção do projeto e outra para construir os testes.

Nota

Eu sei que há outras maneiras de fazer isso, incluindo autoconf e outras soluções automáticas. No entanto, eu gostaria de entender o que está acontecendo e ser capaz de escrever os makefiles a partir do zero, apesar de sua possível impraticabilidade.

Qualquer orientação ou dicas seria apreciada. Obrigado!

[Edit]

Assim, os três soluções dadas até agora são os seguintes:

  • arquivos de cabeçalho globalmente usado Inserir em um diretório include paralelo
  • usar o caminho no satement #include como em #include "../src/foo.h"
  • usar a opção -I para informar o compilador de incluir locais

Até agora eu como a solução chave -I porque não envolve a alteração de código fonte quando as mudanças de estrutura de diretório.

Foi útil?

Solução

Para test_foo.c você simplesmente precisa dizer ao compilador onde os arquivos de cabeçalho pode ser encontrado. Por exemplo.

gcc -I../src -c test_foo.c

Em seguida, o compilador irá também olhar para este diretório para buscar os arquivos de cabeçalho. Em test_foo.c você escreve então:

#include "foo.h"

Editar : Para ligação contra foo.c, na verdade contra foo.o, é preciso mencioná-lo na lista de arquivos objeto. Eu suponho que você já tem os arquivos de objetos, em seguida, fazer depois disso:

gcc test_foo.o ../src/foo.o -o test

Outras dicas

Eu também raramente uso do GNU autotools. Em vez disso, eu vou colocar um único makefile artesanais no diretório raiz.

Para obter todos os cabeçalhos no diretório de origem, use algo como isto:

get_headers = $(wildcard $(1)/*.h)
headers := $(call get_headers,src)

Em seguida, você pode usar o seguinte para tornar o objeto-arquivos no diretório de teste dependem desses cabeçalhos:

test/%.o : test/%.c $(headers)
    gcc -std=c99 -pedantic -Wall -Wextra -Werror $(flags) -Isrc -g -c -o $@ $<

Como você pode ver, eu não sou fã de built-in directivas. Observe também o interruptor -I.

Obter uma lista de objetos-arquivos para um diretório é um pouco mais complicado:

get_objects = $(patsubst %.c,%.o,$(wildcard $(1)/*.c))
test_objects = $(call get_objects,test)

A regra a seguir faria os objetos para os testes:

test : $(test_objects)

A regra test não deve apenas tornar os arquivos objeto, mas os executáveis. Como escrever a regra depende da estrutura de seus testes:. Por exemplo, você poderia criar um executável para cada arquivo .c ou apenas um único que testa todos

Uma maneira comum de fazer isso é para arquivos de cabeçalho utilizados por um único arquivo C para ser nomeado o mesmo que o arquivo C e no mesmo diretório, e para o cabeçalho arquivos usados ??por muitos arquivos C (especialmente aqueles utilizados pelo conjunto projeto) para estar em um include diretório que é paralelo ao diretório de origem C.

Seu arquivo de teste apenas deve incluir os arquivos de cabeçalho diretamente usando caminhos relativos, como este:

#include "../src/foo.h"
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top