Compilando o código C / C ++ incluindo instruções de compilação do pré-processador em um arquivo de origem C / C ++ real

0

Então aqui está a coisa, e é realmente apenas conceitual, então não deixe isso te incomodar:

Tenho motivos para não querer confiar em um sistema de criação específico. Eu não quero desanimar ninguém, mas eu realmente só quero me ater ao que vem com o compilador. Neste caso, o GCC. Automake tem certos problemas de compatibilidade, especialmente com o Windows. < 3 O GNU make é tão limitado que geralmente precisa ser complementado com scripts de shell. Os scripts do shell podem assumir muitas formas e, para encurtar a história e provavelmente irritar muitas pessoas, aqui está o que eu quero fazer -

O principal ponto de entrada é Deus. Seja um arquivo de origem C ou C ++, é o centro do aplicativo. Não só quero que o ponto de entrada principal seja a primeira coisa que é executada, como também quero que seja a primeira coisa que é compilada. Deixe-me explicar -

Houve um tempo em que as bibliotecas proprietárias e de código fechado eram comuns. Graças à mudança da Apple para o Unix e a Microsoft, atirando no pé, esse tempo acabou. Qualquer biblioteca que precise ser vinculada dinamicamente pode ser incluída como um arquivo de suporte do aplicativo. Por essa razão, instruções de compilação separadas para .SOs (e talvez .DLLs;]) são todas finas e elegantes, porque são arquivos executáveis separados. Qualquer outra biblioteca deve estar vinculada estaticamente. Agora, vamos falar sobre link estático -

A ligação estática é uma verdadeira puta. É para isso que os makefiles são. Se todo o projeto foi escrito em um idioma (por exemplo, C ou C ++), você pode #incluir as bibliotecas como cabeçalhos. Tudo bem. Mas agora, vamos considerar outro cenário -

Digamos que você seja como eu e não seja difícil descobrir a difícil desculpa de C para strings, então você decide usar o C ++. Mas você quer usar uma biblioteca C, como por exemplo o MiniBasic. Deus nos ajude. Se a biblioteca C não foi projetada para estar em conformidade com a sintaxe do C ++, você está ferrado. É quando entram os makefiles, já que você precisa compilar o arquivo-fonte C com um compilador C e o arquivo-fonte C ++ com um compilador C ++. Eu não quero usar makefiles. Fique comigo -

Espero que exista uma maneira de explorar as macros de pré-processamento do GCC para dizer algo assim:

Hi, GCC. How are you doing? In case you forgot, this source file you're looking at right now is written in C++. You should of course compile it with G++. There's another file that this file needs, but it's written in C. It's called "lolcats.c". I want you to compile that one with GCC into an object file and I want you to compile this one with G++ into the main object file, then I want you to link them together into an executable file.

Como posso escrever uma coisa dessas na linguagem de pré-processamento? O GCC até faz isso?

    
por user78076 20.07.2014 / 04:03

4 respostas

6

The main entry point is God. Be it a C or C++ source file, it is the center of the application.

Apenas da mesma forma que o nitrogênio é o centro de um pinheiro . É onde tudo começa , mas não há nada sobre C ou C ++ que faça você colocar o "centro" da sua aplicação em main() .

Muitos programas C e C ++ são criados em um loop de eventos ou em um I / O pump . Esses são os "centros" de tais programas. Você nem precisa colocar esses loops no mesmo módulo como main() .

Not only do I want the main entry point to be the first thing that is executed, I also want it to be the first thing that is compiled.

Na verdade, é mais fácil colocar main() último em um arquivo de origem C ou C ++.

C e C ++ não são como alguns idiomas, onde os símbolos podem ser usados antes de serem declarados. Colocar main() primeiro significa que você declara para frente todo o resto.

There was a time when proprietary and closed-source libraries were common. Thanks to Apple switching to Unix and Microsoft shooting themselves in the foot, that time is over.

" Diga-me que está sonhando! "

OS X e iOS estão cheios de código proprietário, e a Microsoft não irá embora em breve.

O que as dificuldades atuais da Microsoft têm a ver com a sua pergunta? Você diz que pode querer criar DLLs e menciona a incapacidade do Automake de lidar efetivamente com o Windows. Isso me diz que a Microsoft continua relevante em seu mundo também.

Static linking is a real bitch.

Realmente? Eu sempre achei mais fácil do que vincular a bibliotecas dinâmicas. É uma tecnologia mais antiga e simples, com menos coisas para dar errado.

Vinculação estática incorpora as dependências externas no executável, de modo que o executável permaneça sozinho, autocontido. Do restante da sua pergunta, isso deve agradar a você.

you can #include the libraries as headers

Não ... Você #include cabeçalhos da biblioteca , não bibliotecas.

Isso não é apenas pedantismo. A terminologia é importante . Tem significado.

Se você pudesse usar #include libraries, #include </usr/lib/libfoo.a> funcionaria.

Em muitas linguagens de programação, é o modo como as referências externas a módulos / bibliotecas funcionam. Ou seja, você faz referência ao código externo diretamente.

C e C ++ não estão entre as linguagens que funcionam dessa maneira.

If the C library wasn't designed to conform to C++'s syntax, you're screwed.

Não, você só precisa aprender a usar o C ++. Especificamente, aqui, extern "C" .

How might I write such a thing in preprocessor lingo?

É perfeitamente legal para #include outro arquivo C ou C ++:

#include <some/library/main.cpp>

#include <some/other/library/main.c>
#include <some/other/library/secondary_module.c>

#include <iostream>

int main()
{
   call_the_library();
   do_other_stuff();
   return 0;
}

Nós não usamos extern "C" aqui porque isto extrai o código C e C ++ dessas outras bibliotecas diretamente para o nosso arquivo C ++, então os módulos C precisam ser legais também. Há um número de pequenas diferenças entre C e C ++ , mas se você vai misturar duas línguas, você terá que saber como lidar com elas de qualquer maneira.

Outra parte complicada de fazer isso é que a ordem do #includes é mais sensível que a ordem das referências da biblioteca se um comando do vinculador. Quando você ignora o vinculador dessa forma, acaba tendo que fazer algumas coisas manualmente que o vinculador faria de outra forma para você automaticamente.

Para provar isso, eu peguei MiniBasic (seu próprio exemplo) e converti sua% programa de driverscript.c para um programa C ++ autônomo que diz #include <basic.c> em vez de #include <basic.h> . ( patch ) Apenas para provar que é realmente um programa em C ++ agora, mudei todas as chamadas printf() para cout stream insertions. / p>

Eu tive que fazer algumas outras mudanças, todas bem dentro de um dia de trabalho normal para alguém que vai misturar C e C ++:

  1. O código MiniBasic faz uso da disposição de C para tolerar conversões automáticas de void* para qualquer outro tipo de ponteiro. C ++ faz com que você seja explícito.

  2. Novos compiladores não estão mais tolerando o uso de constantes de string C (por exemplo, "Hello, world!\n" ) em char* contextts. O padrão diz que o compilador tem permissão para colocá-los em memória somente leitura, então você precisa usar const char* .

É isso. Apenas alguns minutos de trabalho, corrigindo reclamações do GCC.

Eu tive que fazer algumas alterações semelhantes em basic.c àquelas no arquivo de patch script.c vinculado. Eu não me importei em postar os diffs, já que eles são mais do mesmo.

Para outra maneira de fazer isso, estude a Mistura de SQLite , em comparação com a árvore de fontes do SQLite . O SQLite não usa #include todos os outros arquivos em um único arquivo mestre; eles são, na verdade, concatenados juntos, mas isso também é tudo que o #include faz em C ou C ++.

    
por 20.07.2014 / 05:18
1

O gcc irá compilar C e C e C ++ como C ++ simplesmente como resultado de você nomear os arquivos apropriadamente, o pré-processador não entra nisso. Você precisará de extern "C" de blocos em torno de suas declarações em C em seus arquivos C ++ para certificar-se de que o vinculador pode vincular o material corretamente.

Mas o que você está descrevendo quase nunca será útil. Se você estiver usando uma biblioteca que precisa de algum tipo de configuração para compilar, ela ainda precisará dela se você tentar compilar os arquivos diretamente no seu projeto. Não são muitas as bibliotecas não triviais do mundo real que são puramente ISO C que serão compiladas em todas as plataformas sem modificação ou algum tipo de script de configuração, então você estaria criando complexidade na maioria das vezes, não reduzindo, porque você vai tem que lidar com essa configuração em sua própria construção de alguma forma.

    
por 20.07.2014 / 05:57
1

Não, você não pode fazer isso. Não há nenhum pragma do gcc para compilar desta forma . O mais semelhante é o Microsoft Visual C ++ #pragma comment(lib, …) ou #pragma comment(linker, …) [ 1 ] [2 ] por notar que algumas bibliotecas devem ser incluídas no procedimento de link.

Hi, GCC. How are you doing? In case you forgot, this source file you're looking at right now is written in C++. You should of course compile it with G++. There's another file that this file needs, but it's written in C. It's called "lolcats.c". I want you to compile that one with GCC into an object file and I want you to compile this one with G++ into the main object file, then I want you to link them together into an executable file.

Sua solicitação é exatamente o que um Makefile faz.

Você pode criar um script de shell que extraia os arquivos de origem e os compila com qualquer comando que você queira usar. Mas é a solução errada ™

Se você tiver vários arquivos, armazene-os como vários arquivos. Se você quiser que as pessoas não usem o make ou o cmake, não forneça um Makefile / CMakefile . Dê a eles, por exemplo, um arquivo compile-me.sh .

O único caso em que sinto que estou em uma situação semelhante é quando codifico um utilitário em um único arquivo, mas simplesmente forneço o comando de compilação no topo dentro de um comentário.

    
por 20.07.2014 / 15:59
0

Você pode decidir que todas as suas coisas são plugins. Em seguida, compile-os com gcc -shared -fPIC -O thing1.cc -o thing1.so e tenha um programa stub principal fazendo dlopen (3) em ./thing1.so then dlsym on God ; no Linux você pode ter truques binfmt_misc para tornar isso mais transparente.

Se você insistir em ter programas autocontidos, observe que o GCC tem as -offestanding que você precisaria de interface, veja syscalls (2) ). Estude cuidadosamente as especificações relevantes da ABI . Para Linux / x86-64, é aqui . Leia sobre as convenções de chamada .

Você também pode personalizar o GCC com plug-ins do compilador como o MELT (então você pode adicionar um #pragma que faria coisas arbitrárias, talvez mesmo forçando um gcc ...)

BTW, um ponto de entrada como seu God não é um arquivo de origem, mas algum rótulo conhecido pelo linker.

Lendo mais sobre compiladores , linkers (consulte o livro de Levine: Linkers e Loaders , arquivos de objetos , ELF , bibliotecas e objetos compartilhados (veja Documento do Drepper : Como escrever bibliotecas compartilhadas ...), crt0.o deve ajudar.

Veja também o projeto de proposta do módulo C ++ N3347

    
por 20.07.2014 / 13:31