The 2.1.5 version has now entered the final stage. This version has added a large wave of new features. It is currently undergoing stability testing and repair. Here, let's first introduce what new features and improvements have been introduced in the new version.
1. 提供类似cmake的find_*系列接口,实现各种查找,例如:find_package, find_library, find_file, ...
2. 提供模块接口,实现编译器的各种检测,例如:has_features, has_flags, has_cincludes, has_cfuncs, ...
3. 实现大量扩展模块,提供文件下载、解压缩、git操作等接口
4. 支持预编译头文件支持,改进c++编译效率
5. 支持在工程中自定义模块进行扩展
6. 提供代码片段检测接口,实现更加灵活定制化的检测需求
7. 改进option和target,提供更加动态化的配置
8. 通过find_package实现包依赖管理2.0版本
9. 改进root权限问题,实现更加安全的root下运行
10. 提供compile_commands.json导出插件
11. 改进vs201x工程生成插件,支持多模式、多架构同时构建和自由切换不干扰
Use find_package to find dependent packages
This interface refers to the cmake find_*
's design of a series of interfaces to realize dynamic search and add package dependencies in the project.
target("test")
set_kind("binary")
add_files("*.c")
on_load(function (target)
import("lib.detect.find_package")
target:add(find_package("zlib"))
end)
The above description code uses lib.detect.find_package to find the package. If the package is found zlib
, then add links
, includedirs
and linkdirs
other information to the target.
Implement package management 2.0
Before the 2.1.4 version, xmake used the built-in pkg/zlib.pkg
method of the project to detect the link for package management. Although it also supports automatic detection, the search function is limited, and the built-in binary libraries of various architectures to the project are not very good for git. friendly.
Now through find_package
and option
, we can achieve better package management:
option("zlib")
set_showmenu(true)
before_check(function (option)
import("lib.detect.find_package")
option:add(find_package("zlib"))
end)
target("test")
add_options("zlib")
By defining a package named as zlib option, associated with target, before the options is checked to find zlib package from the system, if present, is added to the corresponding links
, linkdirs
other configuration information, and then detecting the option, if the option is detected by , This target will enable zlib when compiling.
If you want to manually disable this zlib package so that it does not participate in automatic detection and linking, you only need to:
$ xmake f --zlib=n
$ xmake
Note: Version 2.2.1 will implement package management 3.0, more automated dependent package management and use, see: Remote package management for specific details .
E.g:
add_requires("mbedtls master optional")
add_requires("pcre2 >=1.2.0", "zlib >= 1.2.11")
add_requires("[email protected]:glennrp/libpng.git@libpng >=1.6.28")
target("test")
add_packages("pcre2", "zlib", "libpng", "mbedtls")
It is currently under development, so please look forward to it. .
Custom extension of the module
We can xmake.lua
expand the modules directory by specifying at the beginning of the project file:
add_moduledirs("$(projectdir)/xmake/modules")
In this way, xmake can find custom extension modules, for example:
projectdir
- xmake
- modules
- detect/package/find_openssl.lua
By adding a find_openssl.lua
script to the custom project module directory , it can be extended find_package
to make the package search more accurate.
Here is a summary of find_package
the search order:
- If you specify a
{packagedirs = ""}
parameter, the local package will be searched first from the path specified by this parameter*.pkg
- If
xmake/modules
there is adetect.packages.find_xxx
script below , then try to call this script to improve the search results - If the system exists
pkg-config
and the library of the system environment is searched, trypkg-config
to find it using the provided path and link information - If the system exists
homebrew
, and the library of the system environment is searched, trybrew --prefix xxx
to find it using the provided information - Parameters specified in the path pathes path and some known systems
/usr/lib
,/usr/include
the lookup
Quickly judge the compiler feature detection support
Through core.tool.compiler
the compiler.has_features interface of the module , you xmake.lua
can prejudge the language features supported by the current compilation period in the module to achieve conditional compilation.
Here is also a reference to the cmake design, see: issues#83 for specific details .
target("test")
on_load(function (target)
import("core.tool.compiler")
if compiler.has_features("cxx_constexpr") then
target:add("defines", "HAS_CXX_CONSTEXPR=1")
end
end)
The code, when loading the target, and determine the current compiler supports constant expression syntax characteristic of c ++, if you add support for macro definitions: HAS_CXX_CONSTEXPR=1
.
We can also add some parameters to control compilation options when judging, for example, the above features need to be c++11
supported, we can enable it:
if compiler.has_features({
"c_static_assert", "cxx_constexpr"}, {languages = "cxx11"}) then
-- ok
end
If the target has been set before c++11
, then we can also pass in the target object and inherit all the settings of the target:
if compiler.has_features("cxx_constexpr", {target = target, defines = "..", includedirs = ".."}) then
-- ok
end
For a list of all c/c++ compiler features, see: compiler.features
Determine whether the specified c/c++ header file exists
Use lib.detect.has_cincludes to detect the existence of c header files.
import("lib.detect.has_cincludes")
local ok = has_cincludes("stdio.h")
local ok = has_cincludes({
"stdio.h", "stdlib.h"}, {target = target})
local ok = has_cincludes({
"stdio.h", "stdlib.h"}, {defines = "_GNU_SOURCE=1", languages = "cxx11"})
For the detection of c++ header files, see: lib.detect.has_cxxincludes
Determine whether the specified c/c++ function exists
Through lib.detect.has_cfuncs to detect whether the c function exists.
import("lib.detect.has_cfuncs")
local ok = has_cfuncs("setjmp")
local ok = has_cfuncs({
"sigsetjmp((void*)0, 0)", "setjmp"}, {includes = "setjmp.h"})
For the detection of c++ functions, see: lib.detect.has_cxxfuncs .
Determine whether the specified c/c++ type exists
Through lib.detect.has_ctypes to detect whether the c function exists.
import("lib.detect.has_ctypes")
local ok = has_ctypes("wchar_t")
local ok = has_ctypes({
"char", "wchar_t"}, {includes = "stdio.h"})
local ok = has_ctypes("wchar_t", {includes = {
"stdio.h", "stdlib.h"}, "defines = "_GNU_SOURCE=1", languages = "cxx11"})
For c++ type detection, see: lib.detect.has_cxxtypes .
Check whether the c/c++ code fragment can be compiled
The universal c/c++ code snippet detection interface, by passing in multiple code snippet lists, it will automatically generate a compilation file, and then compile it with common sense, and return true if the compilation passes.
For some complex compiler features, when even compiler.has_features cannot be detected, you can use this interface to detect it by trying to compile.
import("lib.detect.check_cxsnippets")
local ok = check_cxsnippets("void test() {}")
local ok = check_cxsnippets({
"void test(){}", "#define TEST 1"}, {types = "wchar_t", includes = "stdio.h"})
This interface is a general version of interfaces such as detect.has_cfuncs , detect.has_cincludes and detect.has_ctypes , and it is also more low-level.
So we can use it to detect: types, functions, includes and links, or combine them to detect.
The first parameter is a list of code snippets, which is generally used for the detection of some custom features. If it is empty, you can only detect the conditions in the optional parameters, for example:
local ok = check_cxsnippets({}, {types = {
"wchar_t", "char*"}, includes = "stdio.h", funcs = {
"sigsetjmp", "sigsetjmp((void*)0, 0)"}})
The above call will check whether the types, includes and funcs are all satisfied at the same time, and return true if it passes.
More powerful xmake lua plugin
In version 2.1.4, this plug-in already supports REPL (read-eval-print), which enables interactive operation to facilitate testing modules:
$ xmake lua
> 1 + 2
3
> a = 1
> a
1
> for _, v in pairs({
1, 2, 3}) do
>> print(v)
>> end
1
2
3
Now you can test the module interface more quickly with one line of command:
$ xmake lua lib.detect.find_package openssl
The returned results are as follows:{links = {"ssl", "crypto", "z"}, linkdirs = {"/usr/local/lib"}, includedirs = {"/usr/local/include"}}
Precompiled header file support
xmake adds pre-compiled header files to speed up c/c++
program compilation, currently supported compilers are: gcc, clang and msvc.
The usage is as follows:
target("test")
set_precompiled_header("header.h")
Normally, to set the pre-compilation of the c header file, you need to add this configuration. If it is the pre-compilation of the c++ header file, change it to
target("test")
set_precompiled_header("header.hpp")
The parameter specifies the path of the header file that needs to be precompiled, relative to the current xmake.lua
directory.
If you just call the xmake command line for direct compilation, then the above settings are sufficient, and various compilers have been supported, but in some cases, the above settings cannot meet the requirements:
- If you want to use the
xmake project
project plug-in to generate the vs project file, there is still a lack of a similarstdafx.cpp
file (the above setting will automatically generate a temporary when msvc compiles, but it is not friendly to IDE projects). - If you
header.h
want to use gcc/clang as a precompiled header file for c++, it will not be supported unless you change itheader.hpp
(the default will be precompiled as a c header file).
Therefore, in order to be more versatile cross-platform, you can create a similar project in vc inside stdafx.cpp
source file: header.cpp
.
target("test")
set_precompiled_header("header.h", "header.cpp")
header.cpp
The contents are as follows:
#include "header.h"
The above settings can handle the pre-compilation processing in various situations well, and the addition header.cpp
also tells xmake: it header.h
is pre-compiled as C++.
Compared with the stdafx.cpp
sum in the classic vc project stdafx.h
, it can also perfectly support:
target("test")
set_precompiled_header("stdafx.h", "stdafx.cpp")
Generate compiler_commands plugin
Extension xmake project
project generation plug-in, support compiler_commands.json
file output, used to export the compilation information of each source file, generate a compiled database file based on clang, in json format, which can be used to interact with ide, editor, and static analysis tools.
$ xmake project -k compile_commands
The output content format is as follows:
[
{ "directory": "/home/user/llvm/build",
"command": "/usr/bin/clang++ -Irelative -DSOMEDEF=\"With spaces, quotes and \\-es.\" -c -o file.o file.cc",
"file": "file.cc" },
...
]
Generally used to integrate with IDEs, editor plug-ins, and static analysis tools. For compile_commands
detailed instructions, see: https://clang.llvm.org/docs/JSONCompilationDatabase.html ">JSONCompilationDatabase
Custom option detection script
Before option detection, some configuration conditions are dynamically added:
option("zlib")
before_check(function (option)
import("lib.detect.find_package")
option:add(find_package("zlib"))
end)
By overwriting the detection script, the detection result of the control option:
option("test")
add_deps("small")
set_default(true)
on_check(function (option)
if option:dep("small"):enabled() then
option:enable(false)
end
end)
If the test dependent option passes, the test option is disabled.
After the option detection is completed, execute this script to do some post-processing, or you can disable the option again at this time:
option("test")
add_deps("small")
add_links("pthread")
after_check(function (option)
option:enable(false)
end)
Custom target load script
When the target is initialized and loaded, on_load will be executed , and some dynamic target configuration can be done in it to achieve more flexible target description definition, for example:
target("test")
on_load(function (target)
target:add("defines", "DEBUG", "TEST=\"hello\"")
target:add("linkdirs", "/usr/lib", "/usr/local/lib")
target:add({includedirs = "/usr/include", "links" = "pthread"})
end)
You can dynamically add various target attributes on_load
through target:set
, inside target:add
.
Target custom build script supports sub-platform architecture
By setting 平台|架构
parameters, the execution conditions of custom scripts are controlled, so that different scripts can be called to build under different platforms and architectures:
target("test")
on_build("iphoneos|arm*", function (target)
-- TODO
end)
Or for all macosx platforms, execute the script:
target("test")
after_build("macosx", function (target)
-- TODO
end)
Other scripts, such as: on_clean
, before_package
etc. are also supported Oh, and before 2.1.4 only supports:
target("test")
on_package(function (target)
-- TODO
end)
It cannot deal with different architectures and platforms separately.
Get the value of a built-in variable
Built-in variables can be directly obtained through this interface, without the need for additional $()
packages, which makes it easier to use, for example:
print(val("host"))
print(val("env PATH"))
local s = val("shell echo hello")
Using vformat is more cumbersome:
local s = vformat("$(shell echo hello)")
However, it vformat
supports string parameter formatting and is more powerful, so the application scenarios are different.
Goal depends on achieving property inheritance
In versions prior to 2.1.4, target.add_deps is only used to add dependencies and modify the compilation order:
target("test1")
set_kind("static")
set_files("*.c")
target("test2")
set_kind("static")
set_files("*.c")
target("demo")
add_deps("test1", "test2")
add_links("test1", "test2")
add_linkdirs("test1dir", "test2dir")
After version 2.1.5, the target will also automatically inherit the configuration and attributes in the dependent target, no additional calls are needed add_links
, add_includedirs
and the add_linkdirs
interface to associate the dependent target with the other interface is no longer required . The above code can be simplified to:
target("test1")
set_kind("static")
set_files("*.c")
target("test2")
set_kind("static")
set_files("*.c")
target("demo")
add_deps("test1", "test2") -- 会自动链接依赖目标
And the inheritance relationship supports cascade, for example:
target("library1")
set_kind("static")
add_files("*.c")
add_headers("inc1/*.h")
target("library2")
set_kind("static")
add_deps("library1")
add_files("*.c")
add_headers("inc2/*.h")
target("test")
set_kind("binary")
add_deps("library2")
New search tool interface
The lib.detect.find_tool interface is used to find executable programs. It is more advanced and powerful than lib.detect.find_program . It encapsulates executable programs and provides the concept of tools:
- toolname: tool name, referred to as an executable program, used to identify a tool, such as:
gcc
,clang
etc. - program: executable program command, for example:
xcrun -sdk macosx clang
lib.detect.find_program
It can only be judged whether the program exists through the original program command or path passed in.
Instead, find_tool
you can find the tool through a more consistent toolname, and return the full command path of the corresponding program, for example:
import("lib.detect.find_tool")
local tool = find_tool("clang")
We can also specify {version = true}
parameters to get the version of the tool, and specify a custom search path, and also support built-in variables and custom scripts:
local tool = find_tool("clang", {check = "--help"})
local tool = find_tool("clang", {check = function (tool) os.run("%s -h", tool) end})
local tool = find_tool("clang", {version = true, {pathes = {
"/usr/bin", "/usr/local/bin", "$(env PATH)", function () return "/usr/xxx/bin" end}})
Finally, find_tool
the search process is summarized :
- First pass
{program = "xxx"}
the parameters to try to run and test. - If
xmake/modules/detect/tools
the presence ofdetect.tools.find_xxx
the script, the script calls this a more accurate detection. - Try to check from
/usr/bin
,/usr/local/bin
wait for the system catalog.
We can also project in xmake.lua
the add_moduledirs
specified module directory, add a custom look for scripts to improve the detection mechanisms:
projectdir
- xmake/modules
- detect/tools/find_xxx.lua
More secure root permission compilation
Since xmake provides powerful support for custom modules and scripts, and has built-in actions such as installation and uninstallation, xmake.lua
improper script descriptions can easily lead to overwriting system files. Therefore, the new version has made improvements:
- To compile the project under root, first determine the user authority attribute of the project directory, and try to lower the authority to a non-root user for compilation.
- If you need to write some system files, you will be prompted that the current permissions are not safe, and it is forbidden to continue running unless you add
--root
parameters to force root to run. - If the current project directory has root user authority, the same as 2.
For details, see: pull#113
API interface improvements
Use includes to replace the old add_subdirs and add_subfiles interfaces.
Use set_config_header to replace the old set_config_h and set_config_h_prefix interfaces.
Add a large number of expansion modules
- file download
- unzip
- git operation and other interfaces
For details, see the document: Extension Module