12月
12
その4の続き
C++ だとどうでしょうか。
umezawa@selene ~$ cat callee_cpp.cc int func_cpp(int x, int y, int z) { return x * y + z; } umezawa@selene ~$ cat main_cpp.cpp #include <stdio.h> int func_cpp(int x, int y, int z); int main(void) { printf("%d\n", func_cpp(2, 3, 4)); return 0; } umezawa@selene ~$ g++ -o callee_cpp_gcc.obj -c callee_cpp.cc
c:\cygwin\home\umezawa>cl /Fea5.exe main_cpp.cpp callee_cpp_gcc.obj Microsoft(R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86 Copyright (C) Microsoft Corporation. All rights reserved. main_cpp.cpp Microsoft (R) Incremental Linker Version 14.00.24215.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:a5.exe main_cpp.obj callee_cpp_gcc.obj main_cpp.obj : error LNK2019: 未解決の外部シンボル "int __cdecl func_cpp(int,int,int)" (?func_cpp@@YAHHHH@Z) が関数 _main で参照されました。 a5.exe : fatal error LNK1120: 1 件の未解決の外部参照
リンクできません。
objdump で見てみると、名前修飾規則が異なっていることが分かります。
umezawa@selene ~$ objdump --syms callee_cpp_gcc.obj callee_cpp_gcc.obj: ファイル形式 pe-i386 SYMBOL TABLE: [ 0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x00000000 callee_cpp.cc File [ 2](sec 1)(fl 0x00)(ty 20)(scl 2) (nx 1) 0x00000000 __Z8func_cppiii AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0 [ 4](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .text AUX scnlen 0x13 nreloc 0 nlnno 0 [ 6](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .data AUX scnlen 0x0 nreloc 0 nlnno 0 [ 8](sec 3)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .bss AUX scnlen 0x0 nreloc 0 nlnno 0 [ 10](sec 4)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .rdata$zzz AUX scnlen 0x11 nreloc 0 nlnno 0 [ 12](sec 5)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .eh_frame AUX scnlen 0x38 nreloc 1 nlnno 0
ググってみると、以下のように記述すると、修飾後の名前を直接指定できるようです。
umezawa@selene ~$ cat callee_cpp2.cc int func_cpp(int x, int y, int z) __asm__("_mangled_name"); int func_cpp(int x, int y, int z) { return x * y + z; } umezawa@selene ~$ g++ -o callee_cpp2_gcc.obj -c callee_cpp2.cc umezawa@selene ~$ objdump --syms callee_cpp2_gcc.obj callee_cpp2_gcc.obj: ファイル形式 pe-i386 SYMBOL TABLE: [ 0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x00000000 callee_cpp2.cc File [ 2](sec 1)(fl 0x00)(ty 20)(scl 2) (nx 1) 0x00000000 _mangled_name AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0 [ 4](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .text AUX scnlen 0x13 nreloc 0 nlnno 0 [ 6](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .data AUX scnlen 0x0 nreloc 0 nlnno 0 [ 8](sec 3)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .bss AUX scnlen 0x0 nreloc 0 nlnno 0 [ 10](sec 4)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .rdata$zzz AUX scnlen 0x11 nreloc 0 nlnno 0 [ 12](sec 5)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .eh_frame AUX scnlen 0x38 nreloc 1 nlnno 0
ですが、名前に ?
や @
が含まれるとエラーになるため、Visual C++ と互換性のある名前にはできません。できたとしても全ての関数について Visual C++ での修飾後の名前を調べる作業が発生し、めんどくさいことになります。
extern "C"
している場合はフリー関数については名前修飾を Visual C++ と互換性のあるもの(C のもの)にできますが、そうした場合関数オーバーロードはできませんし、extern "C"
はクラスのメンバ関数に対しては使えません。おとなしく C++ では諦めた方がよさそうです。これ以上調べるの面倒だし(本音)
その6に続く
Windows 上での Visual C++ と GCC/Clang の相互運用(その6)
その5の続き とてもダメそうな気がしますが、C++ の例外は使えるでしょうか。 その5の結果からクラスオブジェクトが扱えるとは思えないので、とりあえず int でも throw してみます。 um…