--!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-2020, TBOOX Open Source Group. -- -- @author ruki -- @file load.lua -- -- imports import("core.project.config") import("core.project.target") -- make link for framework function _link(framework, major) if major and framework:startswith("Qt") then local debug_suffix = "_debug" if is_plat("windows") then debug_suffix = "d" elseif is_plat("mingw") then debug_suffix = "d" elseif is_plat("android") then debug_suffix = "" end framework = "Qt" .. major .. framework:sub(3) .. (is_mode("debug") and debug_suffix or "") end return framework end -- find the static links from the given qt link directories, e.g. libqt*.a function _find_static_links_3rd(linkdirs, major, libpattern) local links = {} local debug_suffix = "_debug" if is_plat("windows") then debug_suffix = "d" elseif is_plat("mingw") then debug_suffix = "d" elseif is_plat("android") then debug_suffix = "" end for _, linkdir in ipairs(linkdirs) do for _, libpath in ipairs(os.files(path.join(linkdir, libpattern))) do local basename = path.basename(libpath) -- we need ignore qt framework libraries, e.g. libQt5xxx.a, Qt5Core.lib .. if not basename:startswith("libQt" .. major) and not basename:startswith("Qt" .. major) then if (is_mode("debug") and basename:endswith(debug_suffix)) or (not is_mode("debug") and not basename:endswith(debug_suffix)) then table.insert(links, target.linkname(path.filename(libpath))) end end end end return links end -- add plugins function _add_plugins(target, plugins) for name, plugin in pairs(plugins) do target:values_add("qt.plugins", name) if plugin.links then target:values_add("qt.links", unpack(table.wrap(plugin.links))) end if plugin.linkdirs then target:values_add("qt.linkdirs", unpack(table.wrap(plugin.linkdirs))) end end end -- the main entry function main(target, opt) -- init options opt = opt or {} -- get qt sdk local qt = target:data("qt") -- get major version local major = nil if qt.sdkver then major = qt.sdkver:split('%.')[1] end -- add -fPIC target:add("cxflags", "-fPIC") target:add("mxflags", "-fPIC") target:add("asflags", "-fPIC") -- need c++11 at least local languages = target:get("languages") local cxxlang = false for _, lang in ipairs(languages) do if lang:startswith("cxx") or lang:startswith("c++") then cxxlang = true break end end if not cxxlang then target:add("languages", "cxx11") end -- add defines for the compile mode if is_mode("debug") then target:add("defines", "QT_QML_DEBUG") elseif is_mode("release") then target:add("defines", "QT_NO_DEBUG") elseif is_mode("profile") then target:add("defines", "QT_QML_DEBUG", "QT_NO_DEBUG") end -- The following define makes your compiler emit warnings if you use -- any feature of Qt which as been marked deprecated (the exact warnings -- depend on your compiler). Please consult the documentation of the -- deprecated API in order to know how to port your code away from it. target:add("defines", "QT_DEPRECATED_WARNINGS") -- add plugins if opt.plugins then _add_plugins(target, opt.plugins) end local plugins = target:values("qt.plugins") if plugins then local importfile = path.join(config.buildir(), ".qt", "plugin", target:name(), "static_import.cpp") local file = io.open(importfile, "w") if file then file:print("#include ") for _, plugin in ipairs(plugins) do file:print("Q_IMPORT_PLUGIN(%s)", plugin) end file:close() target:add("files", importfile) end end -- backup the user syslinks, we need add them behind the qt syslinks local syslinks_user = target:get("syslinks") target:set("syslinks", nil) -- add qt links and directories for _, qt_linkdir in ipairs(target:values("qt.linkdirs")) do local linkdir = path.join(qt.sdkdir, qt_linkdir) if os.isdir(linkdir) then target:add("linkdirs", linkdir) end end target:add("syslinks", target:values("qt.links")) -- add frameworks if opt.frameworks then target:add("frameworks", opt.frameworks) end -- do frameworks for qt local useframeworks = false for _, framework in ipairs(target:get("frameworks")) do -- translate qt frameworks if framework:startswith("Qt") then -- add defines target:add("defines", "QT_" .. framework:sub(3):upper() .. "_LIB") -- add includedirs if is_plat("macosx") then local frameworkdir = path.join(qt.sdkdir, "lib", framework .. ".framework") if os.isdir(frameworkdir) then target:add("includedirs", path.join(frameworkdir, "Headers")) useframeworks = true else target:add("syslinks", _link(framework, major)) target:add("includedirs", path.join(qt.sdkdir, "include", framework)) end else target:add("syslinks", _link(framework, major)) target:add("includedirs", path.join(qt.sdkdir, "include", framework)) end end end -- add some static third-party links if exists, e.g. libqtmain.a, libqtfreetype.q, libqtlibpng.a -- and exclude qt framework libraries, e.g. libQt5xxx.a, Qt5xxx.lib target:add("syslinks", _find_static_links_3rd(qt.linkdirs, major, is_plat("windows") and "qt*.lib" or "libqt*.a")) -- add user syslinks if syslinks_user then target:add("syslinks", syslinks_user) end -- add includedirs, linkdirs if is_plat("macosx") then target:add("frameworks", "DiskArbitration", "IOKit", "CoreFoundation", "CoreGraphics", "OpenGL") target:add("frameworks", "Carbon", "Foundation", "AppKit", "Security", "SystemConfiguration") if useframeworks then target:add("frameworkdirs", qt.linkdirs) target:add("rpathdirs", "@executable_path/Frameworks", qt.linkdirs) else target:add("rpathdirs", qt.linkdirs) target:add("includedirs", path.join(qt.sdkdir, "include")) -- remove qt frameworks local frameworks = table.wrap(target:get("frameworks")) for i = #frameworks, 1, -1 do local framework = frameworks[i] if framework:startswith("Qt") then table.remove(frameworks, i) end end target:set("frameworks", frameworks) end target:add("includedirs", path.join(qt.sdkdir, "mkspecs/macx-clang")) target:add("linkdirs", qt.linkdirs) elseif is_plat("linux") then target:set("frameworks", nil) target:add("includedirs", path.join(qt.sdkdir, "include")) target:add("includedirs", path.join(qt.sdkdir, "mkspecs/linux-g++")) target:add("rpathdirs", qt.linkdirs) target:add("linkdirs", qt.linkdirs) elseif is_plat("windows") then target:set("frameworks", nil) target:add("includedirs", path.join(qt.sdkdir, "include")) target:add("includedirs", path.join(qt.sdkdir, "mkspecs/win32-msvc")) target:add("linkdirs", qt.linkdirs) target:add("syslinks", "ws2_32", "gdi32", "ole32", "advapi32", "shell32", "user32", "OpenGL32", "imm32", "winmm", "iphlpapi") elseif is_plat("mingw") then target:set("frameworks", nil) target:add("includedirs", path.join(qt.sdkdir, "include")) target:add("includedirs", path.join(qt.sdkdir, "mkspecs/win32-g++")) target:add("linkdirs", qt.linkdirs) target:add("syslinks", "mingw32") elseif is_plat("android") then target:set("frameworks", nil) target:add("includedirs", path.join(qt.sdkdir, "include")) target:add("includedirs", path.join(qt.sdkdir, "mkspecs/android-clang")) target:add("rpathdirs", qt.linkdirs) target:add("linkdirs", qt.linkdirs) end -- is gui application? if opt.gui then -- add -subsystem:windows for windows platform if is_plat("windows") then target:add("defines", "_WINDOWS") local subsystem = false for _, ldflag in ipairs(target:get("ldflags")) do ldflag = ldflag:lower() if ldflag:find("[/%-]subsystem:") then subsystem = true break end end -- maybe user will set subsystem to console if not subsystem then target:add("ldflags", "-subsystem:windows", "-entry:mainCRTStartup", {force = true}) end elseif is_plat("mingw") then target:add("ldflags", "-mwindows", {force = true}) end end end