summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2021-02-19 22:50:53 +0800
committerruki <[email protected]>2021-02-19 22:50:53 +0800
commitc82bda398cadeeeccbdb8804b8bb3d7fe74172dc (patch)
treef40d9ddbb75eb90e6f39d19c28da273d5fb41f36
parent41e6c1d82e6417f8cc0818ae37ee2677fd3692c1 (diff)
add gnu2mslib
-rw-r--r--xmake/modules/detect/tools/find_cmake.lua2
-rw-r--r--xmake/modules/detect/tools/find_ninja.lua2
-rw-r--r--xmake/modules/utils/platform/gnu2mslib.lua113
3 files changed, 115 insertions, 2 deletions
diff --git a/xmake/modules/detect/tools/find_cmake.lua b/xmake/modules/detect/tools/find_cmake.lua
index e227c22a6..7c967f600 100644
--- a/xmake/modules/detect/tools/find_cmake.lua
+++ b/xmake/modules/detect/tools/find_cmake.lua
@@ -49,7 +49,7 @@ function main(opt)
if not program and is_host("windows") then
local msvc = toolchain.load("msvc")
if msvc:check() then
- opt.envs = toolchain.load("msvc"):runenvs() -- we attempt to find it from vstudio environments
+ opt.envs = msvc:runenvs() -- we attempt to find it from vstudio environments
opt.force = true
program = find_program(opt.program or "cmake", opt)
end
diff --git a/xmake/modules/detect/tools/find_ninja.lua b/xmake/modules/detect/tools/find_ninja.lua
index f9f8a08be..36b8b0db8 100644
--- a/xmake/modules/detect/tools/find_ninja.lua
+++ b/xmake/modules/detect/tools/find_ninja.lua
@@ -44,7 +44,7 @@ function main(opt)
if not program and is_host("windows") then
local msvc = toolchain.load("msvc")
if msvc:check() then
- opt.envs = toolchain.load("msvc"):runenvs() -- we attempt to find it from vstudio environments
+ opt.envs = msvc:runenvs() -- we attempt to find it from vstudio environments
opt.force = true
program = find_program(opt.program or "ninja", opt)
end
diff --git a/xmake/modules/utils/platform/gnu2mslib.lua b/xmake/modules/utils/platform/gnu2mslib.lua
new file mode 100644
index 000000000..f32da2060
--- /dev/null
+++ b/xmake/modules/utils/platform/gnu2mslib.lua
@@ -0,0 +1,113 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-present, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file gnu2mslib.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.base.hashset")
+import("core.project.config")
+import("core.tool.toolchain")
+import("lib.detect.find_tool")
+
+-- get .def file path from gnulib
+function _get_defpath_from_gnulib(gnulib, msvc)
+
+ -- check
+ assert(os.isfile(gnulib), "%s not found!", gnulib)
+
+ -- get dumpbin.exe
+ local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "gnu2mslib(): dumpbin.exe not found!")
+
+ -- get symbols
+ local symbols_exported = hashset.new()
+ local symbols = try {function() return os.iorunv(dumpbin.program, {"/linkermember", gnulib}) end}
+ if symbols then
+ local symbols_count
+ local symbols_index = 0
+ for _, line in ipairs(symbols:split('\n', {plain = true})) do
+ if symbols_count == nil then
+ symbols_count = line:match("(%d+) public symbols")
+ if symbols_count then
+ symbols_count = tonumber(symbols_count)
+ end
+ else
+ local symbol = line:match("%s+[%dABCDEF]+%s+(.+)")
+ if symbol then
+ if not symbol:startswith("__") and not symbol:startswith("?") then
+ symbols_exported:insert(symbol)
+ end
+ symbols_index = symbols_index + 1
+ if symbols_index >= symbols_count then
+ break
+ end
+ end
+ end
+ end
+ end
+
+ -- generate .def file
+ if symbols_exported:size() > 0 then
+ local defpath = os.tmpfile() .. ".def"
+ local file = io.open(defpath, "w")
+ file:print("EXPORTS")
+ for _, symbol in ipairs(symbols_exported) do
+ file:print("%s", symbol)
+ end
+ file:close()
+ return defpath
+ end
+end
+
+-- convert mingw/gnu xxx.dll.a to msvc xxx.lib
+--
+-- gnu2mslib(mslib, gnulib_or_defpath, {arch = "x64", dllname = "foo.dll"}
+--
+-- @see https://github.com/xmake-io/xmake/issues/1181
+--
+function main(mslib, gnulib_or_defpath, opt)
+
+ -- check
+ opt = opt or {}
+ assert(is_host("windows"), "we can only run gnu2mslib() on windows!")
+ assert(mslib and gnulib_or_defpath, "invalid input parameters, usage: gnu2mslib(mslib, gnulib_or_defpath, {arch = \"x64\", dllname = \"foo.dll\"})")
+
+ -- get msvc toolchain
+ local msvc = toolchain.load("msvc", {plat = opt.plat, arch = opt.arch})
+ if not msvc:check() then
+ raise("we can not get msvc toolchain!")
+ end
+
+ -- get lib.exe
+ local libtool = assert(find_tool("lib", {envs = msvc:runenvs()}), "gnu2mslib(): lib.exe not found!")
+
+ -- get dll name
+ local dllname = opt.dllname or path.basename(mslib) .. ".dll"
+
+ -- get def file path
+ local defpath = gnulib_or_defpath:endswith(".def") and gnulib_or_defpath or _get_defpath_from_gnulib(gnulib_or_defpath, msvc)
+ assert(defpath and os.isfile(defpath), "gnu2mslib(): convert failed, cannot get .def file!")
+
+ -- generate mslib from gnulib
+ os.vrunv(libtool.program, {"/def:" .. defpath, "/name:" .. path.filename(dllname), "/out:" .. mslib})
+
+ -- remove temporary .def file
+ if not gnulib_or_defpath:endswith(".def") then
+ os.rm(defpath)
+ end
+end