summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2021-08-10 07:39:59 +0800
committerGitHub <[email protected]>2021-08-10 07:39:59 +0800
commit9ded547a6374dcf77b5bd385af5359d4e96f3c22 (patch)
tree98fe9942a10ce358824aa8a8d389bfc1ecb9c31e
parentae33b24ea5ecb6608168e869bb8ee94e0f674c98 (diff)
parent119b04dfa9e6971f324ba65d94737ad7eb31bc83 (diff)
Merge pull request #1562 from xmake-io/runsnippet
Support to run c/c++ snippets for option
-rw-r--r--tests/apis/check_xxx/config.h.in2
-rw-r--r--tests/apis/check_xxx/xmake.lua4
-rw-r--r--xmake/core/base/interpreter.lua17
-rw-r--r--xmake/core/base/scopeinfo.lua16
-rw-r--r--xmake/core/project/option.lua150
-rw-r--r--xmake/includes/check_csnippets.lua30
-rw-r--r--xmake/includes/check_cxxsnippets.lua30
-rw-r--r--xmake/modules/lib/detect/check_cxsnippets.lua53
8 files changed, 255 insertions, 47 deletions
diff --git a/tests/apis/check_xxx/config.h.in b/tests/apis/check_xxx/config.h.in
index c5e178b44..0c7d9ebf8 100644
--- a/tests/apis/check_xxx/config.h.in
+++ b/tests/apis/check_xxx/config.h.in
@@ -8,3 +8,5 @@ ${define HAS_SETJMP}
${define HAS_CONSTEXPR}
${define HAS_CONSEXPR_AND_STATIC_ASSERT}
${define HAS_SSE2}
+${define HAS_LONG_8}
+${define PTR_SIZE}
diff --git a/tests/apis/check_xxx/xmake.lua b/tests/apis/check_xxx/xmake.lua
index a2a5fa0b1..2a9916954 100644
--- a/tests/apis/check_xxx/xmake.lua
+++ b/tests/apis/check_xxx/xmake.lua
@@ -13,6 +13,8 @@ target("test")
check_ctypes("HAS_WCHAR", "wchar_t")
check_cincludes("HAS_STRING_H", "string.h")
+ check_csnippets("HAS_INT_4", "return (sizeof(int) == 4)? 0 : -1;", {tryrun = true})
+ check_csnippets("INT_SIZE", 'printf("%d", sizeof(int)); return 0;', {output = true, number = true})
configvar_check_cincludes("HAS_STRING_AND_STDIO_H", {"string.h", "stdio.h"})
configvar_check_ctypes("HAS_WCHAR_AND_FLOAT", {"wchar_t", "float"})
configvar_check_links("HAS_PTHREAD", {"pthread", "m", "dl"})
@@ -21,3 +23,5 @@ target("test")
configvar_check_features("HAS_CONSTEXPR", "cxx_constexpr", {languages = "c++11"})
configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"})
configvar_check_cflags("HAS_SSE2", "-msse2")
+ configvar_check_csnippets("HAS_LONG_8", "return (sizeof(long) == 8)? 0 : -1;", {tryrun = true})
+ configvar_check_csnippets("PTR_SIZE", 'printf("%d", sizeof(void*)); return 0;', {output = true, number = true})
diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua
index 2f26e20ce..ecfcc7270 100644
--- a/xmake/core/base/interpreter.lua
+++ b/xmake/core/base/interpreter.lua
@@ -1225,13 +1225,19 @@ function interpreter:api_register_set_dictionary(scope_kind, ...)
assert(self)
-- define implementation
- local implementation = function (self, scope, name, dict_or_key, value)
+ local implementation = function (self, scope, name, dict_or_key, value, extra_config)
-- check
if type(dict_or_key) == "table" then
scope[name] = dict_or_key
elseif type(dict_or_key) == "string" and value ~= nil then
scope[name] = {[dict_or_key] = value}
+ -- save extra config
+ if extra_config and table.is_dictionary(extra_config) then
+ scope["__extra_" .. name] = scope["__extra_" .. name] or {}
+ local extrascope = scope["__extra_" .. name]
+ extrascope[dict_or_key] = extra_config
+ end
else
-- error
os.raise("set_%s(%s): invalid value type!", name, type(dict))
@@ -1249,14 +1255,21 @@ function interpreter:api_register_add_dictionary(scope_kind, ...)
assert(self)
-- define implementation
- local implementation = function (self, scope, name, dict_or_key, value)
+ local implementation = function (self, scope, name, dict_or_key, value, extra_config)
-- check
scope[name] = scope[name] or {}
if type(dict_or_key) == "table" then
table.join2(scope[name], dict_or_key)
+ extra_config = value
elseif type(dict_or_key) == "string" and value ~= nil then
scope[name][dict_or_key] = value
+ -- save extra config
+ if extra_config and table.is_dictionary(extra_config) then
+ scope["__extra_" .. name] = scope["__extra_" .. name] or {}
+ local extrascope = scope["__extra_" .. name]
+ extrascope[dict_or_key] = extra_config
+ end
else
-- error
os.raise("add_%s(%s): invalid value type!", name, type(dict))
diff --git a/xmake/core/base/scopeinfo.lua b/xmake/core/base/scopeinfo.lua
index 70755e14a..1f07e236f 100644
--- a/xmake/core/base/scopeinfo.lua
+++ b/xmake/core/base/scopeinfo.lua
@@ -238,7 +238,7 @@ function _instance:_api_add_keyvalues(name, key, ...)
end
-- set the api dictionary to the scope info
-function _instance:_api_set_dictionary(name, dict_or_key, value)
+function _instance:_api_set_dictionary(name, dict_or_key, value, extra_config)
-- get the scope info
local scope = self._INFO
@@ -252,6 +252,12 @@ function _instance:_api_set_dictionary(name, dict_or_key, value)
scope[name] = dict
elseif type(dict_or_key) == "string" and value ~= nil then
scope[name] = {[dict_or_key] = self:_api_handle(value)}
+ -- save extra config
+ if extra_config and table.is_dictionary(extra_config) then
+ scope["__extra_" .. name] = scope["__extra_" .. name] or {}
+ local extrascope = scope["__extra_" .. name]
+ extrascope[dict_or_key] = extra_config
+ end
else
-- error
os.raise("%s:set(%s, ...): invalid value type!", self:kind(), name, type(dict))
@@ -259,7 +265,7 @@ function _instance:_api_set_dictionary(name, dict_or_key, value)
end
-- add the api dictionary to the scope info
-function _instance:_api_add_dictionary(name, dict_or_key, value)
+function _instance:_api_add_dictionary(name, dict_or_key, value, extra_config)
-- get the scope info
local scope = self._INFO
@@ -274,6 +280,12 @@ function _instance:_api_add_dictionary(name, dict_or_key, value)
table.join2(scope[name], dict)
elseif type(dict_or_key) == "string" and value ~= nil then
scope[name][dict_or_key] = self:_api_handle(value)
+ -- save extra config
+ if extra_config and table.is_dictionary(extra_config) then
+ scope["__extra_" .. name] = scope["__extra_" .. name] or {}
+ local extrascope = scope["__extra_" .. name]
+ extrascope[dict_or_key] = extra_config
+ end
else
-- error
os.raise("%s:add(%s, ...): invalid value type!", self:kind(), name, type(dict))
diff --git a/xmake/core/project/option.lua b/xmake/core/project/option.lua
index 93d25990f..e9a2ef20d 100644
--- a/xmake/core/project/option.lua
+++ b/xmake/core/project/option.lua
@@ -68,22 +68,23 @@ function _instance:_clear()
option._cache():set(self:name(), nil)
end
--- check option conditions
-function _instance:_do_check()
+-- check snippets
+function _instance:_do_check_cxsnippts(snippets)
-- import check_cxsnippets()
self._check_cxsnippets = self._check_cxsnippets or sandbox_module.import("lib.detect.check_cxsnippets", {anonymous = true})
-- check for c and c++
- local passed = nil
+ local passed = 0
+ local result_output
for _, kind in ipairs({"c", "cxx"}) do
-- get conditions
- local links = self:get("links")
- local snippets = self:get(kind .. "snippets")
- local types = self:get(kind .. "types")
- local funcs = self:get(kind .. "funcs")
- local includes = self:get(kind .. "includes")
+ local links = self:get("links")
+ local snippets = self:get(kind .. "snippets")
+ local types = self:get(kind .. "types")
+ local funcs = self:get(kind .. "funcs")
+ local includes = self:get(kind .. "includes")
-- TODO it is deprecated
local snippet = self:get(kind .. "snippet")
@@ -100,23 +101,98 @@ function _instance:_do_check()
sourcekind = "cc"
end
- -- check it
- local ok, results_or_errors = sandbox.load(self._check_cxsnippets, snippets, {target = self, sourcekind = sourcekind, types = types, funcs = funcs, includes = includes})
- if not ok then
- return false, results_or_errors
+ -- split snippets
+ local snippets_build = {}
+ local snippets_tryrun = {}
+ local snippets_output = {}
+ if snippets then
+ for name, snippet in pairs(snippets) do
+ if self:extraconf(kind .. "snippets", name, "output") then
+ snippets_output[name] = snippet
+ elseif self:extraconf(kind .. "snippets", name, "tryrun") then
+ snippets_tryrun[name] = snippet
+ else
+ snippets_build[name] = snippet
+ end
+ end
+ if #table.keys(snippets_output) > 1 then
+ return false, -1, string.format("option(%s): only support for only one snippet with output!", self:name())
+ end
+ end
+
+ -- check snippets (run with output)
+ if #table.keys(snippets_output) > 0 then
+ local ok, results_or_errors, output = sandbox.load(self._check_cxsnippets, snippets_output, {
+ target = self,
+ sourcekind = sourcekind,
+ types = types,
+ funcs = funcs,
+ includes = includes,
+ tryrun = true, output = true})
+ if not ok then
+ return false, -1, results_or_errors
+ end
+
+ -- passed or no passed?
+ if results_or_errors then
+ passed = 1
+ result_output = output
+ else
+ passed = -1
+ break
+ end
end
- -- passed?
- if results_or_errors then
- passed = true
- else
- passed = false
- break
+ -- check snippets (run only)
+ if passed == 0 and #table.keys(snippets_tryrun) > 0 then
+ local ok, results_or_errors = sandbox.load(self._check_cxsnippets, snippets_tryrun, {
+ target = self,
+ sourcekind = sourcekind,
+ types = types,
+ funcs = funcs,
+ includes = includes,
+ tryrun = true})
+ if not ok then
+ return false, -1, results_or_errors
+ end
+
+ -- passed or no passed?
+ if results_or_errors then
+ passed = 1
+ else
+ passed = -1
+ break
+ end
+ end
+
+ -- check snippets (build only)
+ if passed == 0 or #table.keys(snippets_build) > 0 then
+ local ok, results_or_errors = sandbox.load(self._check_cxsnippets, snippets_build, {
+ target = self,
+ sourcekind = sourcekind,
+ types = types,
+ funcs = funcs,
+ includes = includes})
+ if not ok then
+ return false, -1, results_or_errors
+ end
+
+ -- passed or no passed?
+ if results_or_errors then
+ passed = 1
+ else
+ passed = -1
+ break
+ end
end
end
end
+ return true, passed, result_output
+end
- -- check features
+-- check features
+function _instance:_do_check_features()
+ local passed = 0
local features = self:get("features")
if features then
@@ -127,23 +203,49 @@ function _instance:_do_check()
features = table.wrap(features)
local features_supported = self._core_tool_compiler.has_features(features, {target = self})
if features_supported and #features_supported == #features then
- passed = true
+ passed = 1
end
-- trace
if baseoption.get("verbose") or baseoption.get("diagnosis") then
for _, feature in ipairs(features) do
- utils.cprint("${dim}checking for feature(%s) ... %s", feature, passed and "${color.success}${text.success}" or "${color.nothing}${text.nothing}")
+ utils.cprint("${dim}checking for feature(%s) ... %s", feature, passed > 0 and "${color.success}${text.success}" or "${color.nothing}${text.nothing}")
end
end
end
+ return true, passed
+end
- -- enable this option if be passed
+-- check option conditions
+function _instance:_do_check()
+
+ -- check snippets
+ local ok, passed, errors = self:_do_check_cxsnippts()
+ if not ok then
+ return false, errors
+ end
+
+ -- get snippet output
+ local output
if passed then
- self:enable(true)
+ output = errors
end
- -- ok
+ -- check features
+ if passed == 0 then
+ ok, passed, errors = self:_do_check_features()
+ if not ok then
+ return false, errors
+ end
+ end
+
+ -- enable this option if be passed
+ if passed > 0 then
+ self:enable(true)
+ if output then
+ self:set_value(output)
+ end
+ end
return true
end
diff --git a/xmake/includes/check_csnippets.lua b/xmake/includes/check_csnippets.lua
index 6cd4ccdc9..06fdc842e 100644
--- a/xmake/includes/check_csnippets.lua
+++ b/xmake/includes/check_csnippets.lua
@@ -23,13 +23,17 @@
-- e.g.
--
-- check_csnippets("HAS_STATIC_ASSERT", "_Static_assert(1, \"\");", {includes = "stdio.h"})
+-- check_csnippets("HAS_LONG_8", "return (sizeof(long) == 8)? 0 : -1;", {tryrun = true})
+-- check_csnippets("PTR_SIZE", 'printf("%d", sizeof(void*)); return 0;', {output = true, number = true})
--
function check_csnippets(definition, snippets, opt)
opt = opt or {}
local optname = "__" .. (opt.name or definition)
option(optname)
- add_csnippets(definition, snippets)
- add_defines(definition)
+ add_csnippets(definition, snippets, {tryrun = opt.tryrun, output = opt.output})
+ if not opt.output then
+ add_defines(definition)
+ end
if opt.links then
add_links(opt.links)
end
@@ -51,6 +55,17 @@ function check_csnippets(definition, snippets, opt)
if opt.warnings then
set_warnings(opt.warnings)
end
+ if opt.output then
+ after_check(function (option)
+ if option:value() then
+ if opt.number then
+ option:add("defines", definition .. "=" .. tonumber(option:value()))
+ else
+ option:add("defines", definition .. "=\"" .. option:value() .. "\"")
+ end
+ end
+ end)
+ end
option_end()
add_options(optname)
end
@@ -60,13 +75,15 @@ end
-- e.g.
--
-- configvar_check_csnippets("HAS_STATIC_ASSERT", "_Static_assert(1, \"\");", {includes = "stdio.h"})
+-- configvar_check_csnippets("HAS_LONG_8", "return (sizeof(long) == 8)? 0 : -1;", {tryrun = true})
+-- configvar_check_csnippets("PTR_SIZE", 'printf("%d", sizeof(void*)); return 0;', {output = true, number = true})
--
function configvar_check_csnippets(definition, snippets, opt)
opt = opt or {}
local optname = "__" .. (opt.name or definition)
local defname, defval = unpack(definition:split('='))
option(optname)
- add_csnippets(definition, snippets)
+ add_csnippets(definition, snippets, {tryrun = opt.tryrun, output = opt.output})
set_configvar(defname, defval or 1)
if opt.links then
add_links(opt.links)
@@ -89,6 +106,13 @@ function configvar_check_csnippets(definition, snippets, opt)
if opt.warnings then
set_warnings(opt.warnings)
end
+ if opt.output then
+ after_check(function (option)
+ if option:value() then
+ option:set("configvar", defname, opt.number and tonumber(option:value()) or option:value())
+ end
+ end)
+ end
option_end()
add_options(optname)
end
diff --git a/xmake/includes/check_cxxsnippets.lua b/xmake/includes/check_cxxsnippets.lua
index 2e906100b..8f0f6f64d 100644
--- a/xmake/includes/check_cxxsnippets.lua
+++ b/xmake/includes/check_cxxsnippets.lua
@@ -23,13 +23,17 @@
-- e.g.
--
-- check_cxxsnippets("HAS_STATIC_ASSERT", "static_assert(1, \"\");")
+-- check_csnippets("HAS_LONG_8", "return (sizeof(long) == 8)? 0 : -1;", {tryrun = true})
+-- check_csnippets("PTR_SIZE", 'printf("%d", sizeof(void*)); return 0;', {output = true, number = true})
--
function check_cxxsnippets(definition, snippets, opt)
opt = opt or {}
local optname = "__" .. (opt.name or definition)
option(optname)
- add_cxxsnippets(definition, snippets)
- add_defines(definition)
+ add_cxxsnippets(definition, snippets, {tryrun = opt.tryrun, output = opt.output})
+ if not opt.output then
+ add_defines(definition)
+ end
if opt.links then
add_links(opt.links)
end
@@ -51,6 +55,17 @@ function check_cxxsnippets(definition, snippets, opt)
if opt.warnings then
set_warnings(opt.warnings)
end
+ if opt.output then
+ after_check(function (option)
+ if option:value() then
+ if opt.number then
+ option:add("defines", definition .. "=" .. tonumber(option:value()))
+ else
+ option:add("defines", definition .. "=\"" .. option:value() .. "\"")
+ end
+ end
+ end)
+ end
option_end()
add_options(optname)
end
@@ -60,13 +75,15 @@ end
-- e.g.
--
-- configvar_check_cxxsnippets("HAS_STATIC_ASSERT", "static_assert(1, \"\");")
+-- configvar_check_cxxsnippets("HAS_LONG_8", "return (sizeof(long) == 8)? 0 : -1;", {tryrun = true})
+-- configvar_check_cxxsnippets("PTR_SIZE", 'printf("%d", sizeof(void*)); return 0;', {output = true, number = true})
--
function configvar_check_cxxsnippets(definition, snippets, opt)
opt = opt or {}
local optname = "__" .. (opt.name or definition)
local defname, defval = unpack(definition:split('='))
option(optname)
- add_cxxsnippets(definition, snippets)
+ add_cxxsnippets(definition, snippets, {tryrun = opt.tryrun, output = opt.output})
set_configvar(defname, defval or 1)
if opt.links then
add_links(opt.links)
@@ -89,6 +106,13 @@ function configvar_check_cxxsnippets(definition, snippets, opt)
if opt.warnings then
set_warnings(opt.warnings)
end
+ if opt.output then
+ after_check(function (option)
+ if option:value() then
+ option:set("configvar", defname, opt.number and tonumber(option:value()) or option:value())
+ end
+ end)
+ end
option_end()
add_options(optname)
end
diff --git a/xmake/modules/lib/detect/check_cxsnippets.lua b/xmake/modules/lib/detect/check_cxsnippets.lua
index aa728e27b..5352301b0 100644
--- a/xmake/modules/lib/detect/check_cxsnippets.lua
+++ b/xmake/modules/lib/detect/check_cxsnippets.lua
@@ -77,7 +77,11 @@ function _sourcecode(snippets, opt)
-- add includes
local sourcecode = ""
- for _, include in ipairs(opt.includes) do
+ local includes = table.wrap(opt.includes)
+ if opt.tryrun and opt.output then
+ table.insert(includes, "stdio.h")
+ end
+ for _, include in ipairs(includes) do
sourcecode = format("%s\n#include <%s>", sourcecode, include)
end
sourcecode = sourcecode .. "\n"
@@ -88,11 +92,13 @@ function _sourcecode(snippets, opt)
end
sourcecode = sourcecode .. "\n"
- -- add snippets
- for _, snippet in pairs(snippets) do
- sourcecode = sourcecode .. "\n" .. snippet
+ -- add snippets (build only)
+ if not opt.tryrun then
+ for _, snippet in pairs(snippets) do
+ sourcecode = sourcecode .. "\n" .. snippet
+ end
+ sourcecode = sourcecode .. "\n"
end
- sourcecode = sourcecode .. "\n"
-- enter main function
sourcecode = sourcecode .. "int main(int argc, char** argv)\n{\n"
@@ -102,10 +108,19 @@ function _sourcecode(snippets, opt)
sourcecode = format("%s\n %s;", sourcecode, _funccode(funcinfo))
end
- -- leave main function
- sourcecode = sourcecode .. "\n return 0;\n}\n"
-
- -- done
+ -- add snippets (tryrun)
+ if opt.tryrun then
+ for _, snippet in pairs(snippets) do
+ sourcecode = sourcecode .. "\n" .. snippet
+ end
+ if opt.output then
+ sourcecode = sourcecode .. "\nfflush(stdout);\n"
+ end
+ sourcecode = sourcecode .. "\n}\n" -- we need return exit code in snippet
+ else
+ -- leave main function
+ sourcecode = sourcecode .. "\n return 0;\n}\n"
+ end
return sourcecode
end
@@ -116,7 +131,8 @@ end
-- e.g.
-- { verbose = false, target = [target|option], sourcekind = "[cc|cxx]"
-- , types = {"wchar_t", "char*"}, includes = "stdio.h", funcs = {"sigsetjmp", "sigsetjmp((void*)0, 0)"}
--- , configs = {defines = "xx", cxflags = ""}}
+-- , configs = {defines = "xx", cxflags = ""}
+-- , tryrun = true, output = true}
--
-- funcs:
-- sigsetjmp
@@ -189,19 +205,30 @@ function main(snippets, opt)
-- @note cannot cache result, all conditions will be changed
-- attempt to compile it
local errors = nil
- local ok = try
+ local ok, output = try
{
function ()
if option.get("diagnosis") then
cprint("${dim}> %s", compiler.compcmd(sourcefile, objectfile, opt))
end
compiler.compile(sourcefile, objectfile, opt)
- if #links > 0 then
+ if #links > 0 or opt.tryrun then
if option.get("diagnosis") then
cprint("${dim}> %s", linker.linkcmd("binary", {"cc", "cxx"}, objectfile, binaryfile, opt))
end
linker.link("binary", {"cc", "cxx"}, objectfile, binaryfile, opt)
end
+ if opt.tryrun then
+ if opt.output then
+ local output = os.iorun(binaryfile)
+ if output then
+ output = output:trim()
+ end
+ return true, output
+ else
+ os.vrun(binaryfile)
+ end
+ end
return true
end,
catch { function (errs) errors = errs end }
@@ -238,6 +265,6 @@ function main(snippets, opt)
if errors and option.get("diagnosis") and #tostring(errors) > 0 then
cprint("${color.warning}checkinfo:${clear dim} %s", errors)
end
- return ok
+ return ok, output
end