去年末に e17 snapshot の cygwin 向け patch をつくった人から出るだろうと思われていた svn の trunk に対する patch が全然出てこないので、しびれを切らして、自分でつくることにした。
去年くらいからの Windows 対応のおかげで共有ライブラリやモジュールの拡張子を ".so" きめうちではなく、OS によって ".dll" にするような処理が既に入っているため、昔ほど手を加える必要はないが、そんな中でも発見できるノウハウはある。
たとえば eina のメモリアロケータモジュールに以下のようなコードがあった。
#ifdef _WIN32 # define MODULE_EXTENSION ".dll" #else # define MODULE_EXTENSION ".so" #endif /* ! _WIN32 */
一見、cygwin では上の define が有効になりそうだが、実際は下の define が有効になり、そのままではモジュールをロードできない。_WIN32 というマクロは意外にも cygwin では定義されないのである。*1
ちなみにマクロ _WIN32 は gcc に -mno-cygwin オプションを指定した場合には定義される。以下に -mno-cygwin オプションの有無による定義済マクロの一覧の差分を示す。
% echo | gcc -v -E -dM - > i686-pc-cygwin.log % echo | gcc -v -E -dM -mno-cygwin - > i686-pc-mingw32.log % diff <(grep define i686-pc-cygwin.log | sort) <(grep define i686-pc-mingw32.log | sort)
--- /dev/fd/63 (grep define i686-pc-cygwin.log | sort) +++ /dev/fd/62 (grep define i686-pc-mingw32.log | sort) @@ -1,7 +1,8 @@ +#define WIN32 1 +#define WINNT 1 +#define _WIN32 1 #define _X86_ 1 #define __CHAR_BIT__ 8 -#define __CYGWIN32__ 1 -#define __CYGWIN__ 1 #define __DBL_DENORM_MIN__ 4.9406564584124654e-324 #define __DBL_DIG__ 15 #define __DBL_EPSILON__ 2.2204460492503131e-16 @@ -49,6 +50,8 @@ #define __LDBL_MIN__ 3.36210314311209350626e-4932L #define __LONG_LONG_MAX__ 9223372036854775807LL #define __LONG_MAX__ 2147483647L +#define __MINGW32__ 1 +#define __MSVCRT__ 1 #define __NO_INLINE__ 1 #define __PTRDIFF_TYPE__ int #define __REGISTER_PREFIX__ @@ -61,6 +64,8 @@ #define __VERSION__ "3.4.4 (cygming special, gdc 0.12, using dmd 0.125)" #define __WCHAR_MAX__ 65535U #define __WCHAR_TYPE__ short unsigned int +#define __WIN32 1 +#define __WIN32__ 1 #define __WINT_TYPE__ unsigned int #define __cdecl __attribute__((__cdecl__)) #define __declspec(x) __attribute__((x)) @@ -70,10 +75,7 @@ #define __stdcall __attribute__((__stdcall__)) #define __tune_i686__ 1 #define __tune_pentiumpro__ 1 -#define __unix 1 -#define __unix__ 1 #define _cdecl __attribute__((__cdecl__)) #define _fastcall __attribute__((__fastcall__)) #define _stdcall __attribute__((__stdcall__)) #define i386 1 -#define unix 1
というわけで patch を ML に投げて、対応してもらった。
#if defined(_WIN32) || defined(__CYGWIN__) # define MODULE_EXTENSION ".dll" #else # define MODULE_EXTENSION ".so" #endif /* !defined(_WIN32) && !defined(__CYGWIN__) */
ところがもっとスマートな方法がある。それは libtool で変数 shrext_cmds にセットされている OS 毎の共有ライブラリおよびモジュールの拡張子を文字列としてソースコードに取り込んで、使うことである。この変数はたとえば、MacOSX (MacPorts) では ".dylib" になる (ただしモジュールは ".so") し、cygwin では ".dll" となる。
% uname Darwin % grep ^shrext_cmds /opt/local/bin/glibtool shrext_cmds="\`test .\$module = .yes && echo .so || echo .dylib\`"
% uname CYGWIN_NT-6.1 % grep ^shrext_cmds /usr/bin/libtool shrext_cmds=".dll"
これを使うと、OS 毎の条件分岐が消えるため、新しい OS に対応する場合も libtool が移植されていれば、ソースコードを書き換える必要はなくなる。
--- src/lib/eina_module.c +++ src/lib/eina_module.c @@ -66,11 +66,7 @@ * @cond LOCAL */ -#if defined(_WIN32) || defined(__CYGWIN__) -# define MODULE_EXTENSION ".dll" -#else -# define MODULE_EXTENSION ".so" -#endif /* !defined(_WIN32) && !defined(__CYGWIN__) */ +#define MODULE_EXTENSION SHARED_LIB_SUFFIX #define EINA_MODULE_SYMBOL_INIT "__eina_module_init" #define EINA_MODULE_SYMBOL_SHUTDOWN "__eina_module_shutdown" --- configure.ac +++ configure.ac @@ -382,6 +382,9 @@ EFL_CHECK_COVERAGE([${enable_tests}], [enable_coverage="yes"], [enable_coverage="no"]) EFL_CHECK_BENCHMARK([enable_benchmark="yes"], [enable_benchmark="no"]) +# Checks for shared library suffix +AC_DEFINE_UNQUOTED(SHARED_LIB_SUFFIX, "$shrext_cmds", [Suffix for shared objects]) + AC_CONFIG_FILES([ Makefile eina-0.pc