diff options
| author | ruki <[email protected]> | 2024-07-14 22:39:14 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2024-07-15 12:21:42 +0800 |
| commit | 6fd249647eb5cf6a44982c35e0564c7733da5457 (patch) | |
| tree | 202e6e520e2ba1b350386cbd2b4a5d38612e3a44 | |
| parent | c58ab2c62721a69b81a127578b88ab678f5dc112 (diff) | |
rewrite install
| -rw-r--r-- | xmake/modules/target/action/install/main.lua | 170 | ||||
| -rw-r--r-- | xmake/modules/target/action/install/unix.lua | 161 | ||||
| -rw-r--r-- | xmake/modules/target/action/install/windows.lua | 159 | ||||
| -rw-r--r-- | xmake/plugins/pack/batchcmds.lua | 68 |
4 files changed, 188 insertions, 370 deletions
diff --git a/xmake/modules/target/action/install/main.lua b/xmake/modules/target/action/install/main.lua index c115e836e..07089c60e 100644 --- a/xmake/modules/target/action/install/main.lua +++ b/xmake/modules/target/action/install/main.lua @@ -18,6 +18,36 @@ -- @file main.lua -- +-- imports +import("core.base.option") +import("core.base.hashset") +import("utils.symbols.depend", {alias = "get_depend_libraries"}) + +function _get_target_package_libfiles(target, opt) + local libfiles = {} + for _, pkg in ipairs(target:orderpkgs(opt)) do + if pkg:enabled() and pkg:get("libfiles") then + for _, libfile in ipairs(table.wrap(pkg:get("libfiles"))) do + local filename = path.filename(libfile) + if filename:endswith(".dll") or filename:endswith(".so") or filename:find("%.so%.%d+$") or filename:endswith(".dylib") then + table.insert(libfiles, libfile) + end + end + end + end + -- we can only reserve used libraries + if target:is_binary() or target:is_shared() then + local depends = hashset.new() + local targetfile = target:targetfile() + local depend_libraries = get_depend_libraries(targetfile, {plat = target:plat(), arch = target:arch()}) + for _, libfile in ipairs(depend_libraries) do + depends:insert(path.filename(libfile)) + end + table.remove_if(libfiles, function (_, libfile) return not depends:has(path.filename(libfile)) end) + end + return libfiles +end + -- install files function _install_files(target) local srcfiles, dstfiles = target:installfiles() @@ -33,25 +63,143 @@ function _install_files(target) end end --- the builtin install main entry -function main(target, opt) +-- install headers +function _install_headers(target, opt) + local includedir = target:includedir() + os.mkdir(includedir) + local srcheaders, dstheaders = target:headerfiles(includedir, {installonly = true}) + if srcheaders and dstheaders then + local i = 1 + for _, srcheader in ipairs(srcheaders) do + local dstheader = dstheaders[i] + if dstheader then + os.vcp(srcheader, dstheader) + end + i = i + 1 + end + end +end + +-- install shared libraries +function _install_shared_libraries(target, opt) + local bindir = target:is_plat("windows", "mingw") and target:bindir() or target:libdir() + + -- get all dependent shared libraries + local libfiles = {} + for _, dep in ipairs(target:orderdeps()) do + if dep:kind() == "shared" then + local depfile = dep:targetfile() + if os.isfile(depfile) then + table.insert(libfiles, depfile) + end + end + table.join2(libfiles, _get_target_package_libfiles(dep, {interface = true})) + end + table.join2(libfiles, _get_target_package_libfiles(target)) + + -- deduplicate libfiles, prevent packages using the same libfiles from overwriting each other + libfiles = table.unique(libfiles) + + -- do install + for _, libfile in ipairs(libfiles) do + local filename = path.filename(libfile) + local filepath = path.join(bindir, filename) + if os.isfile(filepath) then + wprint("'%s' already exists in install dir, we are copying '%s' to overwrite it.", filepath, libfile) + end + os.cp(libfile, filepath) + end +end + +-- install binary +function _install_binary(target, opt) + local bindir = target:bindir() + os.mkdir(bindir) + os.vcp(target:targetfile(), bindir) + os.trycp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile()))) + _install_shared_libraries(target, opt) +end + +-- install shared library +function _install_shared(target, opt) + local bindir = target:is_plat("windows", "mingw") and target:bindir() or target:libdir() + os.mkdir(bindir) + local targetfile = target:targetfile() + + if target:is_plat("windows", "mingw") then + -- install *.lib for shared/windows (*.dll) target + -- @see https://github.com/xmake-io/xmake/issues/714 + os.vcp(target:targetfile(), bindir) + local libdir = target:libdir() + local targetfile_lib = path.join(path.directory(targetfile), path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib")) + if os.isfile(targetfile_lib) then + os.mkdir(libdir) + os.vcp(targetfile_lib, libdir) + end + else + -- install target with soname and symlink + if os.islink(targetfile) then + local targetfile_with_soname = os.readlink(targetfile) + if not path.is_absolute(targetfile_with_soname) then + targetfile_with_soname = path.join(target:targetdir(), targetfile_with_soname) + end + if os.islink(targetfile_with_soname) then + local targetfile_with_version = os.readlink(targetfile_with_soname) + if not path.is_absolute(targetfile_with_version) then + targetfile_with_version = path.join(target:targetdir(), targetfile_with_version) + end + os.vcp(targetfile_with_version, bindir, {symlink = true, force = true}) + end + os.vcp(targetfile_with_soname, bindir, {symlink = true, force = true}) + os.vcp(targetfile, bindir, {symlink = true, force = true}) + else + os.vcp(targetfile, bindir) + end + end + os.trycp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile()))) + + _install_headers(target, opt) + _install_shared_libraries(target, opt) +end - -- get install directory +-- install static library +function _install_static(target, opt) + local libdir = target:libdir() + os.mkdir(libdir) + os.vcp(target:targetfile(), libdir) + os.trycp(target:symbolfile(), path.join(libdir, path.filename(target:symbolfile()))) + _install_headers(target, opt) +end + +-- install headeronly library +function _install_headeronly(target, opt) + _install_headers(target, opt) +end + +-- install moduleonly library +function _install_moduleonly(target, opt) + _install_headers(target, opt) +end + +function main(target, opt) local installdir = target:installdir() if not installdir then + wprint("please use `xmake install -o installdir` or `set_installdir` to set install directory.") return end - - -- trace print("installing %s to %s ..", target:name(), installdir) - -- call script - local install_style = target:is_plat("windows", "mingw") and "windows" or "unix" - local script = import(install_style, {anonymous = true})["install_" .. target:kind()] - if script then - script(target, opt) + if target:is_binary() then + _install_binary(target, opt) + elseif target:is_shared() then + _install_shared(target, opt) + elseif target:is_static() then + _install_static(target, opt) + elseif target:is_headeronly() then + _install_headeronly(target, opt) + elseif target:is_moduleonly() then + _install_moduleonly(target, opt) end - -- install other files _install_files(target) end diff --git a/xmake/modules/target/action/install/unix.lua b/xmake/modules/target/action/install/unix.lua deleted file mode 100644 index dc1354519..000000000 --- a/xmake/modules/target/action/install/unix.lua +++ /dev/null @@ -1,161 +0,0 @@ ---!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 unix.lua --- - --- imports -import("core.base.option") - --- install headers -function _install_headers(target, opt) - local includedir = target:includedir() - os.mkdir(includedir) - local srcheaders, dstheaders = target:headerfiles(includedir, {installonly = true}) - if srcheaders and dstheaders then - local i = 1 - for _, srcheader in ipairs(srcheaders) do - local dstheader = dstheaders[i] - if dstheader then - os.vcp(srcheader, dstheader) - end - i = i + 1 - end - end -end - --- install shared libraries for package -function _install_shared_for_package(target, pkg, outputdir) - _g.installed_libfiles = _g.installed_libfiles or {} - for _, sopath in ipairs(table.wrap(pkg:get("libfiles"))) do - if sopath:endswith(".so") or sopath:match(".+%.so%..+$") or sopath:endswith(".dylib") then - -- prevent packages using the same system libfiles from overwriting each other - if not _g.installed_libfiles[sopath] then - local soname = path.filename(sopath) - local targetname = path.join(outputdir, soname) - if os.isfile(targetname) then - wprint("'%s' already exists in install dir, overwriting it from package(%s).", soname, pkg:name()) - -- rm because symlink cannot overwrite existing file - os.rm(targetname) - end - -- we need to reserve symlink - -- @see https://github.com/xmake-io/xmake/issues/1582 - os.vcp(sopath, outputdir, {symlink = true, force = true}) - _g.installed_libfiles[sopath] = true - end - end - end -end - --- install shared libraries for packages -function _install_shared_for_packages(target, outputdir) - if option.get("nopkgs") then - return - end - _g.installed_packages = _g.installed_packages or {} - for _, pkg in ipairs(target:orderpkgs()) do - if not _g.installed_packages[pkg:name()] then - if pkg:enabled() and pkg:get("libfiles") then - _install_shared_for_package(target, pkg, outputdir) - end - _g.installed_packages[pkg:name()] = true - end - end -end - --- install binary -function install_binary(target, opt) - - -- install binary - local bindir = target:bindir() - os.mkdir(bindir) - os.vcp(target:targetfile(), bindir) - - -- install libraries - local libdir = target:libdir() - os.mkdir(libdir) - - -- install the dependent shared (*.so) target - -- @see https://github.com/xmake-io/xmake/issues/961 - for _, dep in ipairs(target:orderdeps()) do - if dep:kind() == "shared" then - local depfile = dep:targetfile() - if os.isfile(depfile) then - os.vcp(depfile, libdir) - end - end - -- install all shared libraries in packages in all deps - _install_shared_for_packages(dep, libdir) - end - - -- install shared libraries for all packages - _install_shared_for_packages(target, libdir) -end - --- install shared library -function install_shared(target, opt) - - -- install libraries - local libdir = target:libdir() - os.mkdir(libdir) - local targetfile = target:targetfile() - if os.islink(targetfile) then - local targetfile_with_soname = os.readlink(targetfile) - if not path.is_absolute(targetfile_with_soname) then - targetfile_with_soname = path.join(target:targetdir(), targetfile_with_soname) - end - if os.islink(targetfile_with_soname) then - local targetfile_with_version = os.readlink(targetfile_with_soname) - if not path.is_absolute(targetfile_with_version) then - targetfile_with_version = path.join(target:targetdir(), targetfile_with_version) - end - os.vcp(targetfile_with_version, libdir, {symlink = true, force = true}) - end - os.vcp(targetfile_with_soname, libdir, {symlink = true, force = true}) - os.vcp(targetfile, libdir, {symlink = true, force = true}) - else - os.vcp(targetfile, libdir) - end - - -- install shared libraries for all packages - _install_shared_for_packages(target, libdir) - - -- install headers - _install_headers(target, opt) -end - --- install static library -function install_static(target, opt) - - -- install libraries - local libdir = target:libdir() - os.mkdir(libdir) - os.vcp(target:targetfile(), libdir) - - -- install headers - _install_headers(target, opt) -end - --- install headeronly library -function install_headeronly(target, opt) - _install_headers(target, opt) -end - --- install moduleonly library -function install_moduleonly(target, opt) - _install_headers(target, opt) -end diff --git a/xmake/modules/target/action/install/windows.lua b/xmake/modules/target/action/install/windows.lua deleted file mode 100644 index c52c1c934..000000000 --- a/xmake/modules/target/action/install/windows.lua +++ /dev/null @@ -1,159 +0,0 @@ ---!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 windows.lua --- - --- imports -import("core.base.option") -import("lib.detect.find_file") - --- check install directory -function _check_installdir(installdir) - return assert(installdir, "please use `xmake install -o installdir` or `set_installdir` to set install directory on windows.") -end - --- install headers -function _install_headers(target, opt) - local includedir = _check_installdir(target:includedir()) - os.mkdir(includedir) - local srcheaders, dstheaders = target:headerfiles(includedir, {installonly = true}) - if srcheaders and dstheaders then - local i = 1 - for _, srcheader in ipairs(srcheaders) do - local dstheader = dstheaders[i] - if dstheader then - os.vcp(srcheader, dstheader) - end - i = i + 1 - end - end -end - --- install shared libraries for package -function _install_shared_for_package(target, pkg, outputdir) - _g.installed_dllfiles = _g.installed_dllfiles or {} - for _, dllpath in ipairs(table.wrap(pkg:get("libfiles"))) do - if dllpath:endswith(".dll") then - -- prevent packages using the same libfiles from overwriting each other - if not _g.installed_dllfiles[dllpath] then - local dllname = path.filename(dllpath) - if os.isfile(path.join(outputdir, dllname)) then - wprint("'%s' already exists in install dir, overwriting it from package(%s).", dllname, pkg:name()) - end - os.vcp(dllpath, outputdir) - _g.installed_dllfiles[dllpath] = true - end - end - end -end - --- install shared libraries for packages -function _install_shared_for_packages(target, outputdir) - if option.get("nopkgs") then - return - end - _g.installed_packages = _g.installed_packages or {} - for _, pkg in ipairs(target:orderpkgs()) do - if not _g.installed_packages[pkg:name()] then - if pkg:enabled() and pkg:get("libfiles") then - _install_shared_for_package(target, pkg, outputdir) - end - _g.installed_packages[pkg:name()] = true - end - end -end - --- install binary -function install_binary(target, opt) - - -- install binary - local installdir = _get_installdir(target) - local bindir = path.join(installdir, opt and opt.bindir or "bin") - os.mkdir(bindir) - os.vcp(target:targetfile(), bindir) - os.trycp(target:symbolfile(), bindir) - - -- install the dependent shared/windows (*.dll) target - -- @see https://github.com/xmake-io/xmake/issues/961 - _g.installed_dllfiles = _g.installed_dllfiles or {} - for _, dep in ipairs(target:orderdeps()) do - if dep:kind() == "shared" then - local depfile = dep:targetfile() - if os.isfile(depfile) then - if not _g.installed_dllfiles[depfile] then - os.vcp(depfile, bindir) - _g.installed_dllfiles[depfile] = true - end - end - end - -- install all shared libraries in packages in all deps - _install_shared_for_packages(dep, bindir) - end - - -- install shared libraries for all packages - _install_shared_for_packages(target, bindir) -end - --- install shared library -function install_shared(target, opt) - - -- install dll library to the binary directory - local bindir = _check_installdir(target:bindir()) - os.mkdir(bindir) - os.vcp(target:targetfile(), bindir) - os.trycp(target:symbolfile(), bindir) - - -- install *.lib for shared/windows (*.dll) target - -- @see https://github.com/xmake-io/xmake/issues/714 - local targetfile = target:targetfile() - local libdir = _check_installdir(target:libdir()) - local targetfile_lib = path.join(path.directory(targetfile), path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib")) - if os.isfile(targetfile_lib) then - os.mkdir(libdir) - os.vcp(targetfile_lib, libdir) - end - - -- install shared libraries for all packages - _install_shared_for_packages(target, bindir) - - -- install headers - _install_headers(target, opt) -end - --- install static library -function install_static(target, opt) - - -- install library - local libdir = _check_installdir(target:libdir()) - os.mkdir(libdir) - os.vcp(target:targetfile(), libdir) - os.trycp(target:symbolfile(), libdir) - - -- install headers - _install_headers(target, opt) -end - --- install headeronly -function install_headeronly(target, opt) - _install_headers(target, opt) -end - --- install moduleonly -function install_moduleonly(target, opt) - _install_headers(target, opt) -end diff --git a/xmake/plugins/pack/batchcmds.lua b/xmake/plugins/pack/batchcmds.lua index 08216b15e..ff20729eb 100644 --- a/xmake/plugins/pack/batchcmds.lua +++ b/xmake/plugins/pack/batchcmds.lua @@ -61,6 +61,31 @@ function _get_target_installdir(package, target) return path.normalize(installdir) end +function _get_target_package_libfiles(target, opt) + local libfiles = {} + for _, pkg in ipairs(target:orderpkgs(opt)) do + if pkg:enabled() and pkg:get("libfiles") then + for _, libfile in ipairs(table.wrap(pkg:get("libfiles"))) do + local filename = path.filename(libfile) + if filename:endswith(".dll") or filename:endswith(".so") or filename:find("%.so%.%d+$") or filename:endswith(".dylib") then + table.insert(libfiles, libfile) + end + end + end + end + -- we can only reserve used libraries + if target:is_binary() or target:is_shared() then + local depends = hashset.new() + local targetfile = target:targetfile() + local depend_libraries = get_depend_libraries(targetfile, {plat = target:plat(), arch = target:arch()}) + for _, libfile in ipairs(depend_libraries) do + depends:insert(path.filename(libfile)) + end + table.remove_if(libfiles, function (_, libfile) return not depends:has(path.filename(libfile)) end) + end + return libfiles +end + -- install headers function _install_target_headers(target, batchcmds_, opt) local package = opt.package @@ -90,35 +115,10 @@ function _install_target_headers(target, batchcmds_, opt) end end -function _get_target_package_libfiles(target, opt) - local libfiles = {} - for _, pkg in ipairs(target:orderpkgs(opt)) do - if pkg:enabled() and pkg:get("libfiles") then - for _, libfile in ipairs(table.wrap(pkg:get("libfiles"))) do - local filename = path.filename(libfile) - if filename:endswith(".dll") or filename:endswith(".so") or filename:find("%.so%.%d+$") or filename:endswith(".dylib") then - table.insert(libfiles, libfile) - end - end - end - end - -- we can only reserve used libraries - if target:is_binary() or target:is_shared() then - local depends = hashset.new() - local targetfile = target:targetfile() - local depend_libraries = get_depend_libraries(targetfile, {plat = target:plat(), arch = target:arch()}) - for _, libfile in ipairs(depend_libraries) do - depends:insert(path.filename(libfile)) - end - table.remove_if(libfiles, function (_, libfile) return not depends:has(path.filename(libfile)) end) - end - return libfiles -end - -- install target shared libraries function _install_target_shared_libraries(target, batchcmds_, opt) local package = opt.package - local bindir = _get_target_bindir(package, target) + local bindir = target:is_plat("windows", "mingw") and _get_target_bindir(package, target) or _get_target_libdir(package, target) -- get all dependent shared libraries local libfiles = {} @@ -161,7 +161,7 @@ end -- uninstall target shared libraries function _uninstall_target_shared_libraries(target, batchcmds_, opt) local package = opt.package - local bindir = _get_target_bindir(package, target) + local bindir = target:is_plat("windows", "mingw") and _get_target_bindir(package, target) or _get_target_libdir(package, target) -- get all dependent shared libraries local libfiles = {} @@ -190,24 +190,19 @@ end function _on_target_installcmd_binary(target, batchcmds_, opt) local package = opt.package local bindir = _get_target_bindir(package, target) - - -- install target file batchcmds_:cp(target:targetfile(), path.join(bindir, target:filename())) if os.isfile(target:symbolfile()) then batchcmds_:cp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile()))) end - - -- install target shared libraries _install_target_shared_libraries(target, batchcmds_, opt) end -- on install shared target command function _on_target_installcmd_shared(target, batchcmds_, opt) local package = opt.package - local bindir = _get_target_bindir(package, target) + local bindir = target:is_plat("windows", "mingw") and _get_target_bindir(package, target) or _get_target_libdir(package, target) local libdir = _get_target_libdir(package, target) - -- install target file batchcmds_:cp(target:targetfile(), path.join(bindir, target:filename())) if os.isfile(target:symbolfile()) then batchcmds_:cp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile()))) @@ -222,10 +217,7 @@ function _on_target_installcmd_shared(target, batchcmds_, opt) batchcmds_:cp(targetfile_lib, path.join(libdir, path.filename(targetfile_lib))) end - -- install headers _install_target_headers(target, batchcmds_, opt) - - -- install target shared libraries _install_target_shared_libraries(target, batchcmds_, opt) end @@ -234,13 +226,11 @@ function _on_target_installcmd_static(target, batchcmds_, opt) local package = opt.package local libdir = _get_target_libdir(package, target) - -- install target file batchcmds_:cp(target:targetfile(), path.join(libdir, target:filename())) if os.isfile(target:symbolfile()) then batchcmds_:cp(target:symbolfile(), path.join(libdir, path.filename(target:symbolfile()))) end - -- install headers _install_target_headers(target, batchcmds_, opt) end @@ -310,7 +300,7 @@ end -- on uninstall shared target command function _on_target_uninstallcmd_shared(target, batchcmds_, opt) local package = opt.package - local bindir = _get_target_bindir(package, target) + local bindir = target:is_plat("windows", "mingw") and _get_target_bindir(package, target) or _get_target_libdir(package, target) local libdir = _get_target_libdir(package, target) -- uninstall target file |
