Meu caso de uso é o seguinte para um projeto:
- Arquivo de cabeçalho AC com algumas funções externas declaradas
- Um arquivo de origem C++ com essas funções definidas
- Compilar o código fonte C++ em uma biblioteca compartilhada
- Em um arquivo de origem C, use as funções declaradas no cabeçalho C vinculando-as ao .so
Estou observando algo estranho enquanto faço do. As coisas começam a funcionar com namepsace sem nome.
Aqui está meu arquivo de exemplo:
c_sample.h
:
#include "stddef.h"
extern void hello(void);
extern void bye(void);
cpp_sample.cc
:
#include <iostream>
#include "c_sample.h"
extern "C" {
void hello(void) { std::cout << "HI" << std::endl; }
void bye(void) { std::cout << "BYE" << std::endl; }
}
Ao tentar construir uma biblioteca de compartilhamento, vejo o erro que é esperado, pois c_sample.h
está incluído fora do extern "C"
bloco.
g++ cpp_sample.cc -shared -o libcppsample.so
cpp_sample.cc:5:7: error: declaration of 'hello' has a different language linkage
5 | void hello() { std::cout << "HI" << std::endl;}
| ^
./c_sample.h:3:13: note: previous declaration is here
3 | extern void hello();
| ^
cpp_sample.cc:6:7: error: declaration of 'bye' has a different language linkage
6 | void bye() { std::cout << "BYE" << std::endl;}
| ^
./c_sample.h:4:13: note: previous declaration is here
4 | extern void bye();
| ^
2 errors generated.
No entanto, a mágica acontece no momento em que envolvo isso em um namespace sem nome
cpp_sample.cc
:
#include <iostream>
#include "c_sample.h"
extern "C" {
namespace {
void hello(void) { std::cout << "HI" << std::endl; }
void bye(void) { std::cout << "BYE" << std::endl; }
}
}
Isso foi compilado. E quando tentei usá-lo de outro arquivo de origem C, ele até funcionou
#include "stdio.h"
#include "c_sample.h"
int main() {
hello();
}
$ gcc another.c -L/tmp -lcppsample -o another
$ ./another
HI
Como isso funciona apenas envolvendo-o dentro de um namespace? Como ele é capaz de vincular as funções declaradas com suas definições?