--!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, Xmake Open Source Community. -- -- @author ruki -- @file pkgconfig.lua -- -- imports import("core.base.global") import("core.project.target") import("core.project.config") import("lib.detect.find_file") import("lib.detect.find_library") import("lib.detect.find_tool") -- get pkgconfig function _get_pkgconfig() local pkgconfig = find_tool("pkg-config") or find_tool("pkgconf") if pkgconfig then return pkgconfig.program end end -- get version -- -- @param name the package name -- @param opt the argument options, {configdirs = {"/xxxx/pkgconfig/"}} -- function version(name, opt) -- attempt to add search paths from pkg-config local pkgconfig = _get_pkgconfig() if not pkgconfig then return end -- init options opt = opt or {} -- init PKG_CONFIG_PATH local configdirs_old = os.getenv("PKG_CONFIG_PATH") local configdirs = table.wrap(opt.configdirs) if #configdirs > 0 then os.setenv("PKG_CONFIG_PATH", table.unpack(configdirs)) end -- get version local version = try { function() return os.iorunv(pkgconfig, {"--modversion", name}) end } if version then version = version:trim() end -- restore PKG_CONFIG_PATH if configdirs_old then os.setenv("PKG_CONFIG_PATH", configdirs_old) end -- ok? return version end -- get variables -- -- @param name the package name -- @param variables the variables -- @param opt the argument options, {configdirs = {"/xxxx/pkgconfig/"}} -- function variables(name, variables, opt) opt = opt or {} local pkgconfig = _get_pkgconfig() if not pkgconfig then return end local result = nil local envs = {PKG_CONFIG_PATH = opt.configdirs} if variables then for _, variable in ipairs(table.wrap(variables)) do local value = try { function () return os.iorunv(pkgconfig, {"--variable=" .. variable, name}, {envs = envs}) end } if value ~= nil then result = result or {} result[variable] = value:trim() end end end return result end -- get pcfile path -- -- @param name the package name -- @param opt the argument options, {configdirs = {"/xxxx/pkgconfig/"}} -- function pcfile(name, opt) opt = opt or {} local pkgconfig = _get_pkgconfig() if not pkgconfig then return end local envs = {PKG_CONFIG_PATH = opt.configdirs} local result = try { function () return os.iorunv(pkgconfig, {"--path", name}, {envs = envs}) end } if result then result = result:trim() end return result end -- get library info -- -- @param name the package name -- @param opt the argument options, {version = true, variables = "includedir", configdirs = {"/xxxx/pkgconfig/"}} -- -- @return {links = {"ssl", "crypto", "z"}, linkdirs = {""}, includedirs = {""}, version = ""} -- -- @code -- -- local libinfo = pkgconfig.libinfo("openssl") -- -- @endcode -- function libinfo(name, opt) opt = opt or {} local pkgconfig = _get_pkgconfig() if not pkgconfig then return end -- get cflags local found local result = {} local envs = {PKG_CONFIG_PATH = opt.configdirs} local cflags = try {function () return os.iorunv(pkgconfig, {"--cflags", name}, {envs = envs}) end, catch {function (errs) found = false end}} if cflags then for _, flag in ipairs(os.argv(cflags)) do if flag:startswith("-I") and #flag > 2 then local includedir = flag:sub(3) if includedir and os.isdir(includedir) then result.includedirs = result.includedirs or {} table.insert(result.includedirs, includedir) end elseif flag:startswith("-D") and #flag > 2 then local define = flag:sub(3) result.defines = result.defines or {} table.insert(result.defines, define) elseif flag:startswith("-") and #flag > 1 then result.cxflags = result.cxflags or {} table.insert(result.cxflags, flag) end end end -- libinfo may be empty body, but it's also valid -- @see https://github.com/xmake-io/xmake/issues/3777#issuecomment-1568453316 if found == false then return end -- get libs and ldflags local ldflags = try { function () return os.iorunv(pkgconfig, {"--libs", name}, {envs = envs}) end } if ldflags then for _, flag in ipairs(os.argv(ldflags)) do if flag:startswith("-L") and #flag > 2 then local linkdir = flag:sub(3) if linkdir and os.isdir(linkdir) then result.linkdirs = result.linkdirs or {} table.insert(result.linkdirs, linkdir) end elseif flag:startswith("-l") and #flag > 2 then -- https://github.com/xmake-io/xmake/issues/4292 local link = flag:startswith("-l:") and flag:sub(4) or flag:sub(3) result.links = result.links or {} table.insert(result.links, link) elseif flag:startswith("-") and #flag > 1 then result.ldflags = result.ldflags or {} result.shflags = result.shflags or {} table.insert(result.ldflags, flag) table.insert(result.shflags, flag) end end end -- get version local version = try { function() return os.iorunv(pkgconfig, {"--modversion", name}, {envs = envs}) end } if version then result.version = version:trim() end return result end