Răsfoiți Sursa

fix: 修复windows上无dlfcn的问题

windows上编译使用dlfcn-win32代替dlfcn
VitualMathCore为静态库
SongZihuan 4 ani în urmă
părinte
comite
c2ec62ba90

+ 1 - 1
CMakeLists.txt

@@ -28,4 +28,4 @@ MESSAGE("cmake file in is ${CMAKE_CURRENT_SOURCE_DIR}")
 
 ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/VirtulMathCore)
 ADD_EXECUTABLE(VirtualMath main.c ${SRC_LIST} ${ARGUMENT_LIST})
-TARGET_LINK_LIBRARIES(VirtualMath VirtualMathCore)
+TARGET_LINK_LIBRARIES(VirtualMath VirtualMathCore)

+ 7 - 2
VirtulMathCore/CMakeLists.txt

@@ -16,5 +16,10 @@ AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ofunc/src OFUNC_LIST)
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ofunc/c_lib CLIB_LIST)
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/signalhandler HANDLER_LIST)
 
-ADD_LIBRARY(VirtualMathCore SHARED ${SRC_LIST} ${GC_LIST} ${PASER_LIST} ${MEM_LIST} ${FILE_LIST} ${ARGUMENT_LIST} ${OFUNC_LIST} ${HANDLER_LIST} ${CLIB_LIST})
-TARGET_LINK_LIBRARIES(VirtualMathCore dl)
+ADD_LIBRARY(VirtualMathCore STATIC ${SRC_LIST} ${GC_LIST} ${PASER_LIST} ${MEM_LIST} ${FILE_LIST} ${ARGUMENT_LIST} ${OFUNC_LIST} ${HANDLER_LIST} ${CLIB_LIST})
+IF (NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Windows"))
+    TARGET_LINK_LIBRARIES(VirtualMathCore dl)
+ELSE()
+    ADD_LIBRARY(dlwin32 STATIC src/win/dlfcn_win32.c)
+    TARGET_LINK_LIBRARIES(VirtualMathCore dlwin32)
+ENDIF()

+ 5 - 1
VirtulMathCore/include/macro.h

@@ -1,18 +1,22 @@
 #ifndef VIRTUALMATH_MACRO_H
 #define VIRTUALMATH_MACRO_H
 
-#include <sys/stat.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <sys/stat.h>
 #include <getopt.h>
 #include <unistd.h>
 #include <ctype.h>
 #include <setjmp.h>
 #include <signal.h>
 #include <unistd.h>
+#ifdef __linux__
 #include <dlfcn.h>
+#else
+#include "win/dlfcn_win32.h"
+#endif
 
 // 布尔逻辑的定义
 #define bool int

+ 74 - 0
VirtulMathCore/include/win/dlfcn_win32.h

@@ -0,0 +1,74 @@
+/*
+ * dlfcn-win32
+ * Copyright (c) 2007 Ramiro Polla
+ *
+ * dlfcn-win32 is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * dlfcn-win32 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with dlfcn-win32; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef DLFCN_H
+#define DLFCN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(DLFCN_WIN32_EXPORTS)
+#   define DLFCN_EXPORT __declspec(dllexport)
+#else
+#   define DLFCN_EXPORT
+#endif
+
+/* Relocations are performed when the object is loaded. */
+#define RTLD_NOW    0
+
+/* Relocations are performed at an implementation-defined time.
+ * Windows API does not support lazy symbol resolving (when first reference
+ * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW.
+ */
+#define RTLD_LAZY   RTLD_NOW
+
+/* All symbols are available for relocation processing of other modules. */
+#define RTLD_GLOBAL (1 << 1)
+
+/* All symbols are not made available for relocation processing by other modules. */
+#define RTLD_LOCAL  (1 << 2)
+
+/* These two were added in The Open Group Base Specifications Issue 6.
+ * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
+ */
+
+/* The symbol lookup happens in the normal global scope. */
+#define RTLD_DEFAULT    ((void *)0)
+
+/* Specifies the next object after this one that defines name. */
+#define RTLD_NEXT       ((void *)-1)
+
+/* Open a symbol table handle. */
+DLFCN_EXPORT void *dlopen(const char *file, int mode);
+
+/* Close a symbol table handle. */
+DLFCN_EXPORT int dlclose(void *handle);
+
+/* Get the address of a symbol from a symbol table handle. */
+DLFCN_EXPORT void *dlsym(void *handle, const char *name);
+
+/* Get diagnostic information. */
+DLFCN_EXPORT char *dlerror(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DLFCN_H */

+ 1 - 1
VirtulMathCore/parser/__grammar.c

@@ -1,5 +1,4 @@
 #include "__grammar.h"
-
 /**
  * 二元匹配器
  * twoOperation:
@@ -13,6 +12,7 @@
  * @param self_name 输出值名称(log)
  * @param is_right 表达式是否从右运算到左
  */
+
 inline void twoOperation(PASERSSIGNATURE, PasersFunction callBack, GetSymbolFunction getSymbol, ChecktLeftToken checkleft,
                          int call_type, int self_type, char *call_name, char *self_name, bool is_right) {
     bool is_right_ = false;

+ 1 - 1
VirtulMathCore/src/run.c

@@ -145,7 +145,7 @@ ResultType iterStatement(INTER_FUNCTIONSIG) {
     }
 
     is_KeyInterrupt = signal_reset;
-    signal(SIGINT, signalStopInter);
+    bak = signal(SIGINT, signalStopInter);
     do {
         base = st;
         if (checkSignal(&type, base->line, base->code_file, CALL_INTER_FUNCTIONSIG_NOT_ST(var_list, result, belong)))

+ 4 - 0
VirtulMathCore/src/runfile.c

@@ -7,7 +7,11 @@ int checkFileDir(char **file_dir, INTER_FUNCTIONSIG) {
     {
         char cwd[200] = {};
         char *cwd_tmp = NULL;
+#ifdef __linux__
         getcwd(cwd, 200);
+#else
+        _getcwd(cwd, 200);
+#endif
         cwd_tmp = memStrcat(cwd, "/", false, false);
         cwd_tmp = memStrcat(cwd_tmp, *file_dir, true, false);
         if (checkFile(cwd_tmp) == 1 || checkFile(cwd_tmp = memStrcat(cwd_tmp, ".vm", true, false)) == 1) {

+ 474 - 0
VirtulMathCore/src/win/dlfcn_win32.c

@@ -0,0 +1,474 @@
+/*
+ * dlfcn-win32
+ * Copyright (c) 2007 Ramiro Polla
+ * Copyright (c) 2015 Tiancheng "Timothy" Gu
+ * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
+ *
+ * dlfcn-win32 is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * dlfcn-win32 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with dlfcn-win32; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
+#pragma intrinsic(_ReturnAddress)
+#else
+/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
+#ifndef _ReturnAddress
+#define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0)))
+#endif
+#endif
+
+#ifdef SHARED
+#define DLFCN_WIN32_EXPORTS
+#endif
+#include "win/dlfcn_win32.h"
+
+/* Note:
+ * MSDN says these functions are not thread-safe. We make no efforts to have
+ * any kind of thread safety.
+ */
+
+typedef struct local_object {
+    HMODULE hModule;
+    struct local_object *previous;
+    struct local_object *next;
+} local_object;
+
+static local_object first_object;
+
+/* These functions implement a double linked list for the local objects. */
+static local_object *local_search( HMODULE hModule )
+{
+    local_object *pobject;
+
+    if( hModule == NULL )
+        return NULL;
+
+    for( pobject = &first_object; pobject; pobject = pobject->next )
+        if( pobject->hModule == hModule )
+            return pobject;
+
+    return NULL;
+}
+
+static BOOL local_add( HMODULE hModule )
+{
+    local_object *pobject;
+    local_object *nobject;
+
+    if( hModule == NULL )
+        return TRUE;
+
+    pobject = local_search( hModule );
+
+    /* Do not add object again if it's already on the list */
+    if( pobject )
+        return TRUE;
+
+    for( pobject = &first_object; pobject->next; pobject = pobject->next );
+
+    nobject = (local_object*) malloc( sizeof( local_object ) );
+
+    if( !nobject )
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        return FALSE;
+    }
+
+    pobject->next = nobject;
+    nobject->next = NULL;
+    nobject->previous = pobject;
+    nobject->hModule = hModule;
+
+    return TRUE;
+}
+
+static void local_rem( HMODULE hModule )
+{
+    local_object *pobject;
+
+    if( hModule == NULL )
+        return;
+
+    pobject = local_search( hModule );
+
+    if( !pobject )
+        return;
+
+    if( pobject->next )
+        pobject->next->previous = pobject->previous;
+    if( pobject->previous )
+        pobject->previous->next = pobject->next;
+
+    free( pobject );
+}
+
+/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
+ * static buffer.
+ * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
+ * the limit.
+ */
+static char error_buffer[65535];
+static BOOL error_occurred;
+
+static void save_err_str( const char *str )
+{
+    DWORD dwMessageId;
+    DWORD ret;
+    size_t pos, len;
+
+    dwMessageId = GetLastError( );
+
+    if( dwMessageId == 0 )
+        return;
+
+    len = strlen( str );
+    if( len > sizeof( error_buffer ) - 5 )
+        len = sizeof( error_buffer ) - 5;
+
+    /* Format error message to:
+     * "<argument to function that failed>": <Windows localized error message>
+      */
+    pos = 0;
+    error_buffer[pos++] = '"';
+    memcpy( error_buffer+pos, str, len );
+    pos += len;
+    error_buffer[pos++] = '"';
+    error_buffer[pos++] = ':';
+    error_buffer[pos++] = ' ';
+
+    ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId,
+        MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
+        error_buffer+pos, (DWORD) (sizeof(error_buffer)-pos), NULL );
+    pos += ret;
+
+    /* When FormatMessageA() fails it returns zero and does not touch buffer
+     * so add trailing null byte */
+    if( ret == 0 )
+        error_buffer[pos] = '\0';
+
+    if( pos > 1 )
+    {
+        /* POSIX says the string must not have trailing <newline> */
+        if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
+            error_buffer[pos-2] = '\0';
+    }
+
+    error_occurred = TRUE;
+}
+
+static void save_err_ptr_str( const void *ptr )
+{
+    char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */
+
+#ifdef _MSC_VER
+/* Supress warning C4996: 'sprintf': This function or variable may be unsafe */
+#pragma warning( suppress: 4996 )
+#endif
+    sprintf( ptr_buf, "0x%p", ptr );
+
+    save_err_str( ptr_buf );
+}
+
+/* Load Psapi.dll at runtime, this avoids linking caveat */
+static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded )
+{
+    static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD);
+    HMODULE psapi;
+
+    if( !EnumProcessModulesPtr )
+    {
+        psapi = LoadLibraryA( "Psapi.dll" );
+        if( psapi )
+            EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" );
+        if( !EnumProcessModulesPtr )
+            return 0;
+    }
+
+    return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded );
+}
+
+void *dlopen( const char *file, int mode )
+{
+    HMODULE hModule;
+    UINT uMode;
+
+    error_occurred = FALSE;
+
+    /* Do not let Windows display the critical-error-handler message box */
+    uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+    if( file == 0 )
+    {
+        /* POSIX says that if the value of file is 0, a handle on a global
+         * symbol object must be provided. That object must be able to access
+         * all symbols from the original program file, and any objects loaded
+         * with the RTLD_GLOBAL flag.
+         * The return value from GetModuleHandle( ) allows us to retrieve
+         * symbols only from the original program file. EnumProcessModules() is
+         * used to access symbols from other libraries. For objects loaded
+         * with the RTLD_LOCAL flag, we create our own list later on. They are
+         * excluded from EnumProcessModules() iteration.
+         */
+        hModule = GetModuleHandle( NULL );
+
+        if( !hModule )
+            save_err_str( "(null)" );
+    }
+    else
+    {
+        HANDLE hCurrentProc;
+        DWORD dwProcModsBefore, dwProcModsAfter;
+        char lpFileName[MAX_PATH];
+        size_t i, len;
+
+        len = strlen( file );
+
+        if( len >= sizeof( lpFileName ) )
+        {
+            SetLastError( ERROR_FILENAME_EXCED_RANGE );
+            save_err_str( file );
+            hModule = NULL;
+        }
+        else
+        {
+            /* MSDN says backslashes *must* be used instead of forward slashes. */
+            for( i = 0; i < len; i++ )
+            {
+                if( file[i] == '/' )
+                    lpFileName[i] = '\\';
+                else
+                    lpFileName[i] = file[i];
+            }
+            lpFileName[len] = '\0';
+
+            hCurrentProc = GetCurrentProcess( );
+
+            if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 )
+                dwProcModsBefore = 0;
+
+            /* POSIX says the search path is implementation-defined.
+             * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
+             * to UNIX's search paths (start with system folders instead of current
+             * folder).
+             */
+            hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
+
+            if( !hModule )
+            {
+                save_err_str( lpFileName );
+            }
+            else
+            {
+                if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 )
+                    dwProcModsAfter = 0;
+
+                /* If the object was loaded with RTLD_LOCAL, add it to list of local
+                 * objects, so that its symbols cannot be retrieved even if the handle for
+                 * the original program file is passed. POSIX says that if the same
+                 * file is specified in multiple invocations, and any of them are
+                 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
+                 * symbols will remain global. If number of loaded modules was not
+                 * changed after calling LoadLibraryEx(), it means that library was
+                 * already loaded.
+                 */
+                if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter )
+                {
+                    if( !local_add( hModule ) )
+                    {
+                        save_err_str( lpFileName );
+                        FreeLibrary( hModule );
+                        hModule = NULL;
+                    }
+                }
+                else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter )
+                {
+                    local_rem( hModule );
+                }
+            }
+        }
+    }
+
+    /* Return to previous state of the error-mode bit flags. */
+    SetErrorMode( uMode );
+
+    return (void *) hModule;
+}
+
+int dlclose( void *handle )
+{
+    HMODULE hModule = (HMODULE) handle;
+    BOOL ret;
+
+    error_occurred = FALSE;
+
+    ret = FreeLibrary( hModule );
+
+    /* If the object was loaded with RTLD_LOCAL, remove it from list of local
+     * objects.
+     */
+    if( ret )
+        local_rem( hModule );
+    else
+        save_err_ptr_str( handle );
+
+    /* dlclose's return value in inverted in relation to FreeLibrary's. */
+    ret = !ret;
+
+    return (int) ret;
+}
+
+__declspec(noinline) /* Needed for _ReturnAddress() */
+void *dlsym( void *handle, const char *name )
+{
+    FARPROC symbol;
+    HMODULE hCaller;
+    HMODULE hModule;
+    HANDLE hCurrentProc;
+
+    error_occurred = FALSE;
+
+    symbol = NULL;
+    hCaller = NULL;
+    hModule = GetModuleHandle( NULL );
+    hCurrentProc = GetCurrentProcess( );
+
+    if( handle == RTLD_DEFAULT )
+    {
+        /* The symbol lookup happens in the normal global scope; that is,
+         * a search for a symbol using this handle would find the same
+         * definition as a direct use of this symbol in the program code.
+         * So use same lookup procedure as when filename is NULL.
+         */
+        handle = hModule;
+    }
+    else if( handle == RTLD_NEXT )
+    {
+        /* Specifies the next object after this one that defines name.
+         * This one refers to the object containing the invocation of dlsym().
+         * The next object is the one found upon the application of a load
+         * order symbol resolution algorithm. To get caller function of dlsym()
+         * use _ReturnAddress() intrinsic. To get HMODULE of caller function
+         * use standard GetModuleHandleExA() function.
+         */
+        if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) _ReturnAddress( ), &hCaller ) )
+            goto end;
+    }
+
+    if( handle != RTLD_NEXT )
+    {
+        symbol = GetProcAddress( (HMODULE) handle, name );
+
+        if( symbol != NULL )
+            goto end;
+    }
+
+    /* If the handle for the original program file is passed, also search
+     * in all globally loaded objects.
+     */
+
+    if( hModule == handle || handle == RTLD_NEXT )
+    {
+        HMODULE *modules;
+        DWORD cbNeeded;
+        DWORD dwSize;
+        size_t i;
+
+        /* GetModuleHandle( NULL ) only returns the current program file. So
+         * if we want to get ALL loaded module including those in linked DLLs,
+         * we have to use EnumProcessModules( ).
+         */
+        if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
+        {
+            modules = malloc( dwSize );
+            if( modules )
+            {
+                if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
+                {
+                    for( i = 0; i < dwSize / sizeof( HMODULE ); i++ )
+                    {
+                        if( handle == RTLD_NEXT && hCaller )
+                        {
+                            /* Next modules can be used for RTLD_NEXT */
+                            if( hCaller == modules[i] )
+                                hCaller = NULL;
+                            continue;
+                        }
+                        if( local_search( modules[i] ) )
+                            continue;
+                        symbol = GetProcAddress( modules[i], name );
+                        if( symbol != NULL )
+                        {
+                            free( modules );
+                            goto end;
+                        }
+                    }
+
+                }
+                free( modules );
+            }
+            else
+            {
+                SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+                goto end;
+            }
+        }
+    }
+
+end:
+    if( symbol == NULL )
+    {
+        if( GetLastError() == 0 )
+            SetLastError( ERROR_PROC_NOT_FOUND );
+        save_err_str( name );
+    }
+
+    return *(void **) (&symbol);
+}
+
+char *dlerror( void )
+{
+    /* If this is the second consecutive call to dlerror, return NULL */
+    if( !error_occurred )
+        return NULL;
+
+    /* POSIX says that invoking dlerror( ) a second time, immediately following
+     * a prior invocation, shall result in NULL being returned.
+     */
+    error_occurred = FALSE;
+
+    return error_buffer;
+}
+
+#ifdef SHARED
+BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
+{
+    (void) hinstDLL;
+    (void) fdwReason;
+    (void) lpvReserved;
+    return TRUE;
+}
+#endif