From 0ea2334d46ca84c1a27bd086700f620a06401f94 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Fri, 11 Dec 2020 14:32:52 +0100 Subject: Add function dladdr() and associated test application test-dladdr --- Makefile | 15 +++- src/CMakeLists.txt | 11 ++- src/dlfcn.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/dlfcn.h | 16 ++++ tests/CMakeLists.txt | 8 ++ tests/test-dladdr.c | 184 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 439 insertions(+), 9 deletions(-) create mode 100644 tests/test-dladdr.c diff --git a/Makefile b/Makefile index ab7279b..944358f 100644 --- a/Makefile +++ b/Makefile @@ -6,14 +6,14 @@ CFLAGS = -Wall -O3 -fomit-frame-pointer -Isrc ifeq ($(BUILD_SHARED),yes) TARGETS += libdl.dll - SHFLAGS += -Wl,--out-implib,libdl.dll.a -DSHARED + SHFLAGS += -Wl,--out-implib,libdl.dll.a INSTALL += shared-install - TESTS += test.exe + TESTS += test.exe test-dladdr.exe endif ifeq ($(BUILD_STATIC),yes) TARGETS += libdl.a INSTALL += static-install - TESTS += test-static.exe + TESTS += test-static.exe test-dladdr-static.exe endif ifeq ($(BUILD_MSVC),yes) TARGETS += libdl.lib @@ -32,7 +32,7 @@ libdl.a: $(SOURCES) $(RANLIB) $@ libdl.dll: $(SOURCES) - $(CC) $(CFLAGS) $(SHFLAGS) -shared -o $@ $^ + $(CC) $(CFLAGS) $(SHFLAGS) -DDLFCN_WIN32_SHARED -shared -o $@ $^ libdl.lib: libdl.dll $(LIBCMD) /machine:i386 /def:libdl.def @@ -64,6 +64,12 @@ test.exe: tests/test.c $(TARGETS) test-static.exe: tests/test.c $(TARGETS) $(CC) $(CFLAGS) -o $@ $< libdl.a +test-dladdr.exe: tests/test-dladdr.c $(TARGETS) + $(CC) $(CFLAGS) -DDLFCN_WIN32_SHARED -o $@ $< libdl.dll.a + +test-dladdr-static.exe: tests/test-dladdr.c $(TARGETS) + $(CC) $(CFLAGS) -o $@ $< libdl.a + testdll.dll: tests/testdll.c $(CC) $(CFLAGS) -shared -o $@ $^ @@ -81,6 +87,7 @@ clean:: src/dlfcn.o \ libdl.dll libdl.a libdl.def libdl.dll.a libdl.lib libdl.exp \ tmptest.c tmptest.dll \ + test-dladdr.exe test-dladdr-static.exe \ test.exe test-static.exe testdll.dll testdll2.dll testdll3.dll distclean: clean diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d5296b1..27f9030 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,15 +1,20 @@ set(headers dlfcn.h) set(sources dlfcn.c) -if (BUILD_SHARED_LIBS) - add_definitions(-DSHARED) -endif (BUILD_SHARED_LIBS) add_library(dl ${sources}) # Correctly export the location of installed includes in the target target_include_directories(dl INTERFACE $) +# dot not add -D_EXPORTS +set_target_properties(dl PROPERTIES DEFINE_SYMBOL "") + +# set shared mode for compiling library and propagate mode to cmake clients +if (BUILD_SHARED_LIBS) + target_compile_definitions(dl PUBLIC DLFCN_WIN32_SHARED) +endif (BUILD_SHARED_LIBS) + install (TARGETS dl EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib${LIB_SUFFIX} diff --git a/src/dlfcn.c b/src/dlfcn.c index 3251661..5dd1ccf 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -3,6 +3,7 @@ * Copyright (c) 2007 Ramiro Polla * Copyright (c) 2015 Tiancheng "Timothy" Gu * Copyright (c) 2019 Pali Rohár + * Copyright (c) 2020 Ralf Habacker * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,7 +46,7 @@ #endif #endif -#ifdef SHARED +#ifdef DLFCN_WIN32_SHARED #define DLFCN_WIN32_EXPORTS #endif #include "dlfcn.h" @@ -222,6 +223,7 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); } +DLFCN_EXPORT void *dlopen( const char *file, int mode ) { HMODULE hModule; @@ -329,6 +331,7 @@ void *dlopen( const char *file, int mode ) return (void *) hModule; } +DLFCN_EXPORT int dlclose( void *handle ) { HMODULE hModule = (HMODULE) handle; @@ -353,6 +356,7 @@ int dlclose( void *handle ) } __declspec(noinline) /* Needed for _ReturnAddress() */ +DLFCN_EXPORT void *dlsym( void *handle, const char *name ) { FARPROC symbol; @@ -460,6 +464,7 @@ end: return *(void **) (&symbol); } +DLFCN_EXPORT char *dlerror( void ) { /* If this is the second consecutive call to dlerror, return NULL */ @@ -474,7 +479,212 @@ char *dlerror( void ) return error_buffer; } -#ifdef SHARED +/* See https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2 + * for details */ + +/* Get specific image section */ +static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *size ) +{ + IMAGE_DOS_HEADER *dosHeader; + IMAGE_OPTIONAL_HEADER *optionalHeader; + + dosHeader = (IMAGE_DOS_HEADER *) module; + + if( dosHeader->e_magic != 0x5A4D ) + return FALSE; + + optionalHeader = (IMAGE_OPTIONAL_HEADER *) ( (BYTE *) module + dosHeader->e_lfanew + 24 ); + + if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ) + return FALSE; + + if( index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ) + return FALSE; + + if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 ) + return FALSE; + + if( size != NULL ) + *size = optionalHeader->DataDirectory[index].Size; + + *ptr = (void *)( (BYTE *) module + optionalHeader->DataDirectory[index].VirtualAddress ); + + return TRUE; +} + +/* Return symbol name for a given address */ +static const char *get_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid, void *addr, void **func_address ) +{ + int i; + void *candidateAddr = NULL; + const char *candidateName = NULL; + BYTE *base = (BYTE *) module; /* Required to have correct calculations */ + + for( i = 0; iid[i].Characteristics != 0 && iid[i].FirstThunk != 0; i++ ) + { + IMAGE_THUNK_DATA *thunkILT = (IMAGE_THUNK_DATA *)( base + iid[i].Characteristics ); + IMAGE_THUNK_DATA *thunkIAT = (IMAGE_THUNK_DATA *)( base + iid[i].FirstThunk ); + + for( ; thunkILT->u1.AddressOfData != 0; thunkILT++, thunkIAT++ ) + { + IMAGE_IMPORT_BY_NAME *nameData; + + if( IMAGE_SNAP_BY_ORDINAL( thunkILT->u1.Ordinal ) ) + continue; + + if( (void *) thunkIAT->u1.Function > addr || candidateAddr >= (void *) thunkIAT->u1.Function ) + continue; + + candidateAddr = (void *) thunkIAT->u1.Function; + nameData = (IMAGE_IMPORT_BY_NAME *)( base + (ULONG_PTR) thunkILT->u1.AddressOfData ); + candidateName = (const char *) nameData->Name; + } + } + + *func_address = candidateAddr; + return candidateName; +} + +static BOOL is_valid_address( void *addr ) +{ + MEMORY_BASIC_INFORMATION info; + SIZE_T result; + + if( addr == NULL ) + return FALSE; + + /* check valid pointer */ + result = VirtualQuery( addr, &info, sizeof( info ) ); + + if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS ) + return FALSE; + + return TRUE; +} + +/* Return state if address points to an import thunk + * + * An import thunk is setup with a 'jmp' instruction followed by an + * absolute address (32bit) or relative offset (64bit) pointing into + * the import address table (iat), which is partially maintained by + * the runtime linker. + */ +static BOOL is_import_thunk( void *addr ) +{ + return *(short *) addr == 0x25ff ? TRUE : FALSE; +} + +/* Return adress from the import address table (iat), + * if the original address points to a thunk table entry. + */ +static void *get_address_from_import_address_table( void *iat, DWORD iat_size, void *addr ) +{ + BYTE *thkp = (BYTE *) addr; + /* Get offset from thunk table (after instruction 0xff 0x25) + * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00 + */ + ULONG offset = *(ULONG *)( thkp + 2 ); +#ifdef _WIN64 + /* On 64 bit the offset is relative + * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery> + * And can be also negative (MSVC in WDK) + * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060 + * So cast to signed LONG type + */ + BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset ); +#else + /* On 32 bit the offset is absolute + * 4019b4: ff 25 90 71 40 00 jmp *0x40719 + */ + BYTE *ptr = (BYTE *) offset; +#endif + + if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size ) + return NULL; + + return *(void **) ptr; +} + +/* Holds module filename */ +static char module_filename[2*MAX_PATH]; + +static BOOL fill_module_info( void *addr, Dl_info *info ) +{ + HMODULE hModule; + DWORD dwSize; + + if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL ) + return FALSE; + + dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) ); + + if( dwSize == 0 || dwSize == sizeof( module_filename ) ) + return FALSE; + + info->dli_fbase = (void *) hModule; + info->dli_fname = module_filename; + + return TRUE; +} + +DLFCN_EXPORT +int dladdr( void *addr, Dl_info *info ) +{ + void *realAddr, *funcAddress = NULL; + HMODULE hModule; + IMAGE_IMPORT_DESCRIPTOR *iid; + DWORD iidSize = 0; + + if( addr == NULL || info == NULL ) + return 0; + + hModule = GetModuleHandleA( NULL ); + if( hModule == NULL ) + return 0; + + if( !is_valid_address( addr ) ) + return 0; + + realAddr = addr; + + if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) ) + return 0; + + if( is_import_thunk( addr ) ) + { + void *iat; + void *iatAddr = NULL; + DWORD iatSize = 0; + + if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) + { + /* Fallback for cases where the iat is not defined, + * for example i586-mingw32msvc-gcc */ + if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 ) + return 0; + + iat = (void *)( (BYTE *) hModule + iid->FirstThunk ); + /* We assume that in this case iid and iat's are in linear order */ + iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid ); + } + + iatAddr = get_address_from_import_address_table( iat, iatSize, addr ); + if( iatAddr == NULL ) + return 0; + + realAddr = iatAddr; + } + + if( !fill_module_info( realAddr, info ) ) + return 0; + + info->dli_sname = get_symbol_name( hModule, iid, realAddr, &funcAddress ); + + info->dli_saddr = !info->dli_sname ? NULL : funcAddress ? funcAddress : realAddr; + return 1; +} + +#ifdef DLFCN_WIN32_SHARED BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { (void) hinstDLL; diff --git a/src/dlfcn.h b/src/dlfcn.h index 9ddbba3..164216f 100644 --- a/src/dlfcn.h +++ b/src/dlfcn.h @@ -28,9 +28,13 @@ extern "C" { #endif +#if defined(DLFCN_WIN32_SHARED) #if defined(DLFCN_WIN32_EXPORTS) # define DLFCN_EXPORT __declspec(dllexport) #else +# define DLFCN_EXPORT __declspec(dllimport) +#endif +#else # define DLFCN_EXPORT #endif @@ -59,6 +63,15 @@ extern "C" { /* Specifies the next object after this one that defines name. */ #define RTLD_NEXT ((void *)-1) +/* Structure filled in by dladdr() */ +typedef struct dl_info +{ + const char *dli_fname; /* Filename of defining object (thread unsafe and reused on every call to dladdr) */ + void *dli_fbase; /* Load address of that object */ + const char *dli_sname; /* Name of nearest lower symbol */ + void *dli_saddr; /* Exact value of nearest symbol */ +} Dl_info; + /* Open a symbol table handle. */ DLFCN_EXPORT void *dlopen(const char *file, int mode); @@ -71,6 +84,9 @@ DLFCN_EXPORT void *dlsym(void *handle, const char *name); /* Get diagnostic information. */ DLFCN_EXPORT char *dlerror(void); +/* Translate address to symbolic information (no POSIX standard) */ +DLFCN_EXPORT int dladdr(void *addr, Dl_info *info); + #ifdef __cplusplus } #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5fc6c44..f0871e5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,9 +9,17 @@ target_link_libraries(testdll2 dl) add_library(testdll3 SHARED testdll3.c) set_target_properties(testdll3 PROPERTIES PREFIX "") +add_executable(test-dladdr test-dladdr.c) +target_link_libraries(test-dladdr dl) +if(UNIX) + set_target_properties(test-dladdr PROPERTIES COMPILE_FLAGS "-Wl,--export-dynamic -fpie") +endif() + +install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin) add_executable(t_dlfcn test.c) target_link_libraries(t_dlfcn dl) if(RUN_TESTS) add_test(NAME t_dlfcn COMMAND ${WRAPPER} $ WORKING_DIRECTORY $) + add_test(NAME test-dladdr COMMAND ${WRAPPER} $ WORKING_DIRECTORY $) endif() diff --git a/tests/test-dladdr.c b/tests/test-dladdr.c new file mode 100644 index 0000000..57914cb --- /dev/null +++ b/tests/test-dladdr.c @@ -0,0 +1,184 @@ +/* On Unix like os compile with "-Wl,--export-dynamic -fpie" (default with cmake) */ + +/* required for non Windows builds, must be set in front of the first system include */ +#define _GNU_SOURCE + +#include + +#include +#include +#include + +static int verbose = 0; + +typedef enum { + Pass = 1, + PassWithoutSymbol = 2, + PassWithDifferentAddress = 3, + Fail = 0, + NoInfo = -1, +} ExpectedResult; + +typedef void (* func) (void); + +static void print_dl_info( Dl_info *info, char *prefix, char *suffix ) +{ + printf( "%sfilename: %s base: %p symbol name: '%s' addr: %p%s", prefix, info->dli_fname, info->dli_fbase, info->dli_sname, info->dli_saddr, suffix ); +} + +/** + * @brief check information returned by dladdr + * @param hint text describing what to test + * @param addr address to check + * @param addrsym + * @param expected check against expected result + * @return 0 check passed + * @return 1 check failed + */ +static int check_dladdr( const char *hint, void *addr, char *addrsym, ExpectedResult expected_result ) +{ + Dl_info info; + int result = dladdr( addr, &info ); + int passed = 0; + if (!result) + { + passed = expected_result == NoInfo || expected_result == Fail; + } + else + { + int sym_match = info.dli_sname && strcmp( addrsym, info.dli_sname ) == 0; + int addr_match = addr == info.dli_saddr; + passed = (expected_result == Pass && sym_match && addr_match) + || (expected_result == PassWithoutSymbol && addr_match && !info.dli_sname) + || (expected_result == PassWithDifferentAddress && sym_match && !addr_match) + || (expected_result == Fail && (!sym_match || !addr_match)); + } + printf( "checking '%s' - address %p which should have symbol '%s' -> %s%s", hint, addr, addrsym, passed ? "passed" : "failed", verbose || !passed ? " " : "\n" ); + if( verbose || !passed ) + { + if( !result ) + printf( "(could not get symbol information for address %p)\n", addr ); + else + print_dl_info( &info, "(", ")\n"); + } + return !passed; +} + +#ifdef _WIN32 +/** + * @brief check address from a symbol located in a shared lilbrary + * @param hint text describing what to test + * @param libname libray to get the address from + * @param addrsym symbol to get the address for + * @param should_match result should match the given values + * @return 0 check passed + * @return 1 check failed + * @return 2 failed to open library + * @return 3 failed to get symbol address + */ +static int check_dladdr_by_dlopen( const char *hint, char *libname, char *sym, int should_match ) +{ + void *library = NULL; + void *addr = NULL; + int result; + + library = dlopen( libname, RTLD_GLOBAL ); + if ( library == NULL ) + { + fprintf( stderr, "could not open '%s'\n", libname ); + return 2; + } + + addr = dlsym( library, sym ); + if ( !addr ) { + fprintf( stderr, "could not get address from library '%s' for symbol '%s'\n", libname, sym ); + return 3; + } + + result = check_dladdr( hint, addr, sym, should_match ); + dlclose( library ); + + return result; +} +#endif + +#ifdef _WIN32 +#include +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +/* hide warning "reclared without 'dllimport' attribute" */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#elif defined(_MSC_VER) +/* disable warning C4273 inconsistent dll linkage */ +#pragma warning(push) +#pragma warning(disable: 4273) +#endif +/* + * Windows API functions decorated with WINBASEAPI are imported from iat. + * For testing force linking by import thunk for the following functions + */ +HMODULE WINAPI GetModuleHandleA (LPCSTR lpModuleName); +SIZE_T WINAPI VirtualQuery (LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength); +/* force linking by iat */ +/* WINBASEAPI, which is normally used here, can be overriden by compiler or application, so we cannot use it */ +__declspec(dllimport) HMODULE WINAPI LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +__declspec(dllimport) int __cdecl atoi(const char *_Str); + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) +#endif +#endif + +#ifdef _WIN32 +#define FailOnWin Fail +#else +#define FailOnWin Pass +#endif + +#if defined(_WIN32) && !defined(DLFCN_WIN32_SHARED) +#define PassOnSharedBuild Fail +#else +#define PassOnSharedBuild Pass +#endif + +#define UNUSED(x) (void)x + +int main(int argc, char **argv) +{ + /* points to non reachable address */ + unsigned char zero_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; + /* points to executable base */ + unsigned char invalid_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x40, 0x00 }; + /* no import thunk */ + unsigned char no_import_thunk[6] = { 0xFF, 0x26, 0x00, 0x00, 0x40, 0x00 }; + int result = 0; + UNUSED(argv); + + if (argc == 2) + verbose = 1; + + result = check_dladdr( "null pointer", (void*)0, NULL , NoInfo); + result |= check_dladdr( "invalid pointer", (void*)0x125, NULL , NoInfo); + result |= check_dladdr( "function from dl library", (void*)dladdr, "dladdr" , PassOnSharedBuild ); + result |= check_dladdr( "function from dl library", (void*)dlopen, "dlopen", PassOnSharedBuild ); + result |= check_dladdr( "function from glibc/msvcrt library", (void*)atoi, "atoi", Pass ); + result |= check_dladdr( "function from executable", (void*)main, "main", FailOnWin ); + result |= check_dladdr( "static function from executable", (void*)print_dl_info, "print_dl_info", Fail ); + result |= check_dladdr( "address with positive offset", ((char*)atoi)+1, "atoi", PassWithDifferentAddress ); + result |= check_dladdr( "zero address from import thunk", zero_thunk_address, "", NoInfo ); + result |= check_dladdr( "invalid address from import thunk", invalid_thunk_address, "", NoInfo ); + result |= check_dladdr( "no import thunk", no_import_thunk, "", NoInfo ); + +#ifdef _WIN32 + result |= check_dladdr( "last entry in iat", (void*)VirtualQuery, "VirtualQuery", PassWithDifferentAddress ); + + result |= check_dladdr ( "address through import thunk", (void*)GetModuleHandleA, "GetModuleHandleA", PassWithDifferentAddress ); + result |= check_dladdr_by_dlopen( "address by dlsym", "kernel32.dll", "GetModuleHandleA", Pass ); + + result |= check_dladdr ( "address by image allocation table", (void*)LoadLibraryExA, "LoadLibraryExA", Pass ); + result |= check_dladdr_by_dlopen( "address by dlsym", "kernel32.dll", "LoadLibraryExA", Pass ); +#endif + return result; +} -- cgit v1.2.3-55-g6feb From ebd7badd50aeea37a2ca121409e9f68370b62855 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Sun, 17 Jan 2021 12:51:08 +0100 Subject: cmake: add support to build test-dladdr on unix like os This is used to obtain test result references. --- CMakeLists.txt | 4 +++- tests/CMakeLists.txt | 30 +++++++++++++++++++----------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2202c93..df53be1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,9 @@ else() add_compile_options(-Wall) endif() -add_subdirectory(src) +if(WIN32) + add_subdirectory(src) +endif() if (BUILD_TESTS) add_subdirectory(tests) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f0871e5..00b6647 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,14 +1,25 @@ -include_directories(../src) -add_library(testdll SHARED testdll.c) -set_target_properties(testdll PROPERTIES PREFIX "") +if(WIN32) + include_directories(../src) -add_library(testdll2 SHARED testdll2.c) -set_target_properties(testdll2 PROPERTIES PREFIX "") -target_link_libraries(testdll2 dl) + add_library(testdll SHARED testdll.c) + set_target_properties(testdll PROPERTIES PREFIX "") + + add_library(testdll2 SHARED testdll2.c) + set_target_properties(testdll2 PROPERTIES PREFIX "") + target_link_libraries(testdll2 dl) + + add_library(testdll3 SHARED testdll3.c) + set_target_properties(testdll3 PROPERTIES PREFIX "") + + add_executable(t_dlfcn test.c) + target_link_libraries(t_dlfcn dl) + + if(RUN_TESTS) + add_test(NAME t_dlfcn COMMAND ${WRAPPER} $ WORKING_DIRECTORY $) + endif() +endif() -add_library(testdll3 SHARED testdll3.c) -set_target_properties(testdll3 PROPERTIES PREFIX "") add_executable(test-dladdr test-dladdr.c) target_link_libraries(test-dladdr dl) if(UNIX) @@ -17,9 +28,6 @@ endif() install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin) -add_executable(t_dlfcn test.c) -target_link_libraries(t_dlfcn dl) if(RUN_TESTS) - add_test(NAME t_dlfcn COMMAND ${WRAPPER} $ WORKING_DIRECTORY $) add_test(NAME test-dladdr COMMAND ${WRAPPER} $ WORKING_DIRECTORY $) endif() -- cgit v1.2.3-55-g6feb From 3a016513e42c082c6b7b509bf93f63066a1b65f8 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 28 Dec 2020 12:29:13 +0100 Subject: CI: Add static building for cmake --- .travis.yml | 12 ++++++++- tools/ci-build.sh | 81 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3584048..ba1a8f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,21 @@ language: c compiler: + - x86_64-linux-gnu-gcc - i686-w64-mingw32-gcc - x86_64-w64-mingw32-gcc addons: apt: packages: + - gcc - gcc-mingw-w64 - wine - cmake env: - - ci_buildsys=cmake + - ci_buildsys=cmake ci_variant=static + - ci_buildsys=cmake ci_variant=shared - ci_buildsys=Makefile jobs: @@ -39,5 +42,12 @@ jobs: # Check that we have a real i586-mingw32msvc-gcc compiler as sometimes it is just a symlink to i686-w64-mingw32-gcc before_script: "i586-mingw32msvc-gcc -v 2>&1 | grep -q -x 'Target: i586-mingw32msvc'" + exclude: + # unsupported + - compiler: i686-linux-gnu-gcc + env: ci_buildsys=Makefile + - compiler: x86_64-linux-gnu-gcc + env: ci_buildsys=Makefile + script: - ci_target=${CC%-*} ./tools/ci-build.sh diff --git a/tools/ci-build.sh b/tools/ci-build.sh index 366a407..196fd92 100755 --- a/tools/ci-build.sh +++ b/tools/ci-build.sh @@ -9,35 +9,72 @@ set -x # ci_target: # target to build for -: "${ci_target:=${CROSS_COMPILE%-}}" +: "${ci_target:=x86_64-linux-gnu-gcc}" + +# ci_variant: +# variant to build e.g shared, static +: "${ci_variant:=shared}" + +if test -v CROSS_COMPILE; then + ci_target=${CROSS_COMPILE%-} +fi case "$ci_buildsys" in (Makefile) - ./configure --enable-shared --enable-static --enable-wine --cross-prefix=${ci_target}- - make - make test + case "$ci_target" in + (*mingw32*) + ./configure --enable-shared --enable-static --enable-wine --cross-prefix=${ci_target}- + make + make test + ;; + esac ;; (cmake) + cmake_options=" + --no-warn-unused-cli + -DBUILD_TESTS=1 + -DCMAKE_BUILD_TYPE=RelWithDebInfo + " + case "$ci_variant" in + (shared) + cmake_options+=" -DBUILD_SHARED_LIBS=ON" + ;; + (static) + cmake_options+=" -DBUILD_SHARED_LIBS=OFF" + ;; + esac + cmake --version - rm -rf build - mkdir build - cd build - cmake \ - --no-warn-unused-cli \ - -DCMAKE_FIND_ROOT_PATH=$(${ci_target}-gcc --print-sysroot)/${ci_target} \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_C_COMPILER=$(which ${ci_target}-gcc) \ - -DCMAKE_SYSTEM_PROCESSOR=${ci_target%-*-*} \ - -DCMAKE_CROSSCOMPILING=TRUE \ - -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ - -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \ - -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ - -DCMAKE_SYSTEM_NAME=Windows \ - -DBUILD_TESTS=1 \ - -DENABLE_WINE=ON \ - -DWINE_EXECUTABLE=/usr/bin/wine \ - .. + + # create build dir + rm -rf ci-build-${ci_variant}-${ci_target} + mkdir -p ci-build-${ci_variant}-${ci_target} + cd ci-build-${ci_variant}-${ci_target} + + case "$ci_target" in + (*mingw32*) + cmake \ + -DCMAKE_FIND_ROOT_PATH=$(${ci_target}-gcc --print-sysroot)/${ci_target} \ + -DCMAKE_C_COMPILER=$(which ${ci_target}-gcc) \ + -DCMAKE_SYSTEM_PROCESSOR=${ci_target%-*-*} \ + -DCMAKE_CROSSCOMPILING=TRUE \ + -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ + -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \ + -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ + -DCMAKE_SYSTEM_NAME=Windows \ + -DENABLE_WINE=ON \ + -DWINE_EXECUTABLE=/usr/bin/wine \ + $cmake_options \ + .. + ;; + (*linux*) + cmake \ + $cmake_options \ + .. + ;; + esac + make ctest --output-on-failure make install DESTDIR=$(pwd)/DESTDIR -- cgit v1.2.3-55-g6feb