In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
In this issue, the editor will bring you about how to configure xmake more flexibly through custom scripts. The article is rich in content and analyzes and narrates it from a professional point of view. I hope you can get something after reading this article.
Xmake is a lightweight and modern Lua-based project construction tool for cAccessPlus. Its main features are simple syntax, easy to use, more readable project maintenance, and consistent cross-platform behavior.
How to achieve more complex and flexible customization in the script domain by adding custom scripts.
Configuration separation
Xmake.lua implements the two-layer separate configuration of description domain and script domain by using the "28" principle.
What is the 2008 principle? to put it simply, the configuration of most projects, 80% of the cases, are basic conventional configurations, such as add_cxflags, add_links and so on.
Only less than 20% of the remaining areas need to do some additional complexity to meet some special configuration needs.
The configuration of the remaining 20% is usually complicated, and if it is directly filled with the whole xmake.lua, it will make the configuration of the whole project very confusing and unreadable.
Therefore, xmake isolates 80% of the simple configuration and 20% of the complex configuration by describing the domain and script domain, which makes the whole xmake.lua look very clear and intuitive, with the best readability and maintainability.
Description domain
For novice users who are just getting started, or just maintaining some simple small projects, the requirements are fully met by completely describing the configuration, so what is the description domain? It looks like this:
Target ("test")
Set_kind ("binary")
Add_files ("src/*.c")
Add_defines ("DEBUG")
Add_syslinks ("pthread")
At first glance, it is actually a set_xxx/add_xxx configuration set, for beginners, you can not think of it as a lua script, just as a common configuration file with some basic rules.
Does this look more like a configuration file? In fact, the description domain is a configuration file, similar to the configuration of key/values such as json, so even a novice who doesn't know lua at all can get started quickly.
Moreover, for ordinary projects, only through set_xxx/add_xxx to configure a variety of project settings, has fully met the requirements.
This is what it said at the beginning: in 80% of cases, the simplest configuration rules can be used to simplify the configuration of the project and improve readability and maintainability, which will be very user-friendly and intuitive to both users and developers.
What if we want to make some conditional judgment on different platforms and architectures? It doesn't matter. In addition to the basic configuration, the description domain also supports condition judgment and for loop:
Target ("test")
Set_kind ("binary")
Add_files ("src/*.c")
Add_defines ("DEBUG")
If is_plat ("linux", "macosx") then
Add_links ("pthread", "m", "dl")
End
Target ("test")
Set_kind ("binary")
Add_files ("src/*.c")
Add_defines ("DEBUG")
For _, name in ipairs ({"pthread", "m", "dl"}) do
Add_links (name)
End
Does this look a bit like lua? Although you can usually think of it as a common configuration problem, xmake is based on lua, so the description domain still supports the basic language features of lua.
! > however, it should be noted that although the description domain supports lua script syntax, try not to write too complex lua scripts in the description domain, such as time-consuming function calls and for loops
And in the description domain, the main purpose is to set configuration items, so xmake does not completely open all module interfaces, and many interfaces are prohibited to be called in the description domain.
Even if some callable interfaces are open, they are completely read-only and time-consuming security interfaces, such as: os.getenv () and so on read some general system information for the control of configuration logic.
Another thing to note is that xmake.lua is parsed multiple times to resolve different configuration domains at different stages, such as option (), target () and other fields.
Therefore, don't think about writing complex lua scripts in xmake.lua 's description domain, and don't call print in the description domain to display information, because it will be executed many times, remember: it will be executed many times!
Script field
Limit the description domain to write complex lua, all kinds of lua modules and interfaces can not be used? What shall I do? This is the time for the script field to come out.
If the user is already familiar with the xmake description domain configuration and feels that some of the special configuration maintenance on the project is not satisfied, then we can do more complex configuration logic in the script domain:
Target ("test")
Set_kind ("binary")
Add_files ("src/*.c")
On_load (function (target))
If is_plat ("linux", "macosx") then
Target:add ("links", "pthread", "m", "dl")
End
End)
After_build (function (target))
Import ("core.project.config")
Local targetfile = target:targetfile ()
Os.cp (targetfile, path.join (config.buildir (), path.filename (targetfile)
Print ("build% s", targetfile)
End)
As long as it is similar to the words: on_xxx, after_xxx, before_xxx and other words function body internal scripts, all belong to the script domain.
In the script domain, the user can do anything, and xmake provides an import interface to import various lua modules built into xmake or user-provided lua scripts.
We can implement any function you want in the script field, or even write a separate project.
For some script fragments, if not very bloated, built-in writing like above is enough. If you need to implement more complex scripts and do not want to be filled with a xmake.lua, you can separate the scripts into separate lua files for maintenance.
For example:
Target ("test")
Set_kind ("binary")
Add_files ("src/*.c")
On_load ("modules.test.load")
On_install ("modules.test.install")
We can place custom scripts in the xmake.lua corresponding directory and maintain them independently in modules/test/load.lua and modules/test/install.lua.
A separate lua script file uses main as the main entry, for example:
We can also import some built-in modules or our own extension modules here to use
Import ("core.project.config")
Import ("mymodule")
Function main (target)
If is_plat ("linux", "macosx") then
Target:add ("links", "pthread", "m", "dl")
End
End
In these independent lua scripts, we can also import a variety of built-in modules and custom modules through import, just like writing lua and java.
For the different stages of the domain of the script, on_load is mainly used for target loading, to do some dynamic configuration, unlike the description domain, it will only be executed once!
There are many other stages, such as on/after/before_build/install/package/run, which we will describe in detail below.
Import Import extension Module
Before we explain the various script fields, let's briefly introduce the module import and use of xmake. Xmake uses import to introduce other extension modules, as well as user-defined modules, which can be used in the following places:
Custom script (on_build, on_run..)
Plug-in development
Template development
Platform extension
Custom Task task
The import mechanism is as follows:
Give priority to import from the current script directory
Then import from the extended class library
Imported syntax rules:
Based on. The class library path rules of, for example:
Import ("core.base.option")
Import ("core.base.task")
Function main ()
-- get parameter options
Print (option.get ("version"))
-- run tasks and plug-ins
Task.run ("hello")
End
Import the custom module under the current directory:
Directory structure:
Plugin
-xmake.lua
-main.lua
-modules
-hello1.lua
-hello2.lua
Import modules in main.lua
Import ("modules.hello1")
Import ("modules.hello2")
After import, you can directly use all the public interfaces in it, and the private interfaces are marked with the _ prefix, indicating that they will not be exported and will not be called externally.
In addition to the current directory, we can also import class libraries from other specified directories, such as:
Import ("hello3", {rootdir = "/ home/xxx/modules"})
To prevent naming conflicts, you can also specify aliases after import:
Import ("core.platform.platform", {alias = "p"})
Function main ()
So we can use p to call the plats interface of the platform module to get a list of all the platforms supported by xmake
Print (p.plats ())
End
Two new attributes are added in version 2.1.5: import ("xxx.xxx", {try = true, anonymous = true})
If try is true, if the imported module does not exist, only nil will be returned, and xmake will not be interrupted after throwing an exception.
If anonymous is true, the imported module will not introduce the current scope and only the imported object reference will be returned in the import interface.
Test expansion module
One way we can directly call print in scripts such as on_load to print the result information of the module for testing and verification.
However, xmake also provides the xmake lua plug-in to make testing scripts more flexible and convenient.
Run the specified script file
For example, we can directly specify the lua script to load and run, which is a good way to quickly test some interface modules and verify some of our ideas.
Let's start with a simple lua script:
Function main ()
Print ("hello xmake!")
End
Then just run it directly:
$xmake lua / tmp/test.lua
Call the extension module directly
All the interfaces of built-in modules and extension modules can be called directly through xmake lua, for example:
$xmake lua lib.detect.find_tool gcc
For the above command, we directly call the import ("lib.detect.find_tool") module interface to execute it quickly.
Run an interactive command (REPL)
Sometimes in interactive mode, running commands is more convenient to test and verify some modules and api, but also more flexible, there is no need to write an additional script file to load.
Let's first take a look at how to enter interactive mode:
# execute without any parameters, you can enter
$xmake lua
>
# perform expression evaluation
> 1 + 2
three
# assign and print variable values
> a = 1
> a
one
# multiline input and execution
> for _, v in pairs ({1,2,3}) do
> > print (v)
> > end
one
two
three
We can also import the extension module through import:
> task = import ("core.project.task")
> task.run ("hello")
Hello xmake!
If you want to cancel multi-line input, just enter the character: Q
> for _, v in ipairs ({1,2}) do
> > print (v)
> > Q 1 + 2
three
Target:on_load Custom Target load script
This script will be executed when target initializes the load, in which you can do some dynamic target configuration to achieve more flexible target description definitions, such as:
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)
In on_load, various target attributes can be dynamically added through target:set and target:add, and all set_, add_ configurations that describe the domain can be dynamically configured in this way.
In addition, we can call some APIs of target to get and set some basic information, such as:
Target:on_link Custom Link script
This is a new interface added after v2.2.7 to customize the link process for handling target.
Target ("test")
On_link (function (target))
Print ("link it")
End)
Target:on_build custom compilation script
Override the default build behavior of the target target and implement a custom compilation process, which is generally not required unless you do need to do some compilation that is not provided by xmake by default.
You can customize the compilation operation by overriding it in the following ways:
Target ("test")
-- set up custom compilation scripts
On_build (function (target))
Print ("build it")
End)
Note: after version 2.1.5, all target custom scripts can be handled separately for different platforms and architectures, for example:
Target ("test")
On_build ("iphoneos | arm*", function (target)
Print ("build for iphoneos and arm")
End)
If the first parameter is a string, then specify the platform under which the script needs to be executed | Architecture, and support pattern matching, such as arm* matching all arm schemas.
Of course, you can only set the platform but not the architecture, so that the script can be executed under the specified platform:
Target ("test")
On_build ("windows", function (target)
Print ("build for windows")
End)
Note: once you have set your own build process for this target target, the default build process for xmake will no longer be executed.
Target:on_build_file custom compilation script to realize single file construction
Through this API, you can use hook to specify the built-in construction process of target and re-implement each source file compilation process:
Target ("test")
Set_kind ("binary")
Add_files ("src/*.c")
On_build_file (function (target, sourcefile, opt)
End)
Target:on_build_files custom compilation script to realize multi-file construction
Through this API, you can use hook to specify the built-in build process of target to replace the compilation process of a batch of source files of the same type:
Target ("test")
Set_kind ("binary")
Add_files ("src/*.c")
On_build_files (function (target, sourcebatch, opt)
End)
After setting this interface, the files in the source file list will not appear in the custom target.on_build_file, because this is an inclusion relationship.
Sourcebatch describes these source files of the same type:
Sourcebatch.sourcekind: get the type of the source files, such as cc, as,..
Sourcebatch.sourcefiles (): get a list of source files
Sourcebatch.objectfiles (): get a list of object files
Sourcebatch.dependfiles (): get the list of corresponding dependent files, and store the compilation dependency information in the source file, such as xxx.d
Target:on_clean Custom cleanup script
Overrides the cleaning operation of xmake [c | clean} of the target target to implement a custom cleaning process.
Target ("test")
-- set a custom cleanup script
On_clean (function (target))
-- delete only the target file
Os.rm (target:targetfile ())
End)
Target:on_package Custom Packaging script
Override the packaging operation of the xmake [p | package} of the target target to implement a custom packaging process. If you want to package the specified target into the format you want, you can customize it through this API.
Target ("demo")
Set_kind ("shared")
Add_files ("jni/*.c")
On_package (function (target))
Os.exec (". / gradlew app:assembleDebug")
End)
Of course, this example is a little old, here is just an example of usage, now xmake provides a special xmake-gradle plug-in to better integrate with gradle.
Target:on_install Custom installation script
Override the installation operation of the xmake [I | install} of the target target to implement a custom installation process.
For example, install the generated apk package.
Target ("test")
-- set custom installation scripts and install apk files automatically
On_install (function (target))
-- use adb to install the packaged apk file
Os.run ("adb install-r. / bin/Demo-debug.apk")
End)
Target:on_uninstall custom uninstall script
Overrides the uninstall operation of xmake [u | uninstall} of the target target to implement a custom uninstall process.
Target ("test")
On_uninstall (function (target))
...
End)
Target:on_run custom run script
Overrides the running operation of the xmake [r | run} of the target target to realize the custom running process.
For example, run the installed apk program:
Target ("test")
-- set custom run scripts, automatically run installed app programs, and automatically obtain device output information
On_run (function (target))
Os.run ("adb shell am start-n com.demo/com.demo.DemoTest")
Os.run ("adb logcat")
End)
Before_xxx and after_xxx
It is important to note that all the interfaces of target:on_xxx override the internal default implementation, and usually we don't need to copy completely, just attach some of our own logic, so we can use target:before_xxx and target:after_xxx series scripts.
All on_xxx have corresponding before_ and after_xx versions, and the parameters are exactly the same, for example:
Target ("test")
Before_build (function (target))
Print ("")
End)
Built in module
In the custom script, in addition to using the import interface to import various extension modules, xmake also provides many basic built-in modules, such as: os,io and other basic operations to achieve a more cross-platform processing system interface.
Os.cp
Os.cp behaves similar to the cp command in shell, but is more powerful, not only supporting pattern matching (using lua pattern matching), but also ensuring that the destination path recursive directory creation and support for xmake's built-in variables.
For example:
Os.cp ("$(scriptdir) / * .h", "$(buildir) / inc")
Os.cp ("$(projectdir) / src/test/**.h", "$(buildir) / inc")
The above code copies all the header files under the current xmake.lua directory and the header files under the project source code test directory to the $(buildir) output directory.
Among them, $(scriptdir) and $(projectdir) are built-in variables of xmake. For more information, please see the relevant documentation of built-in variables.
The matching pattern in * .h and * .h is similar to that in add_files, the former is single-level directory matching and the latter is recursive multi-level directory matching.
In the replication above, all files will be expanded and copied to the specified directory, losing the source directory level. If you want to copy according to the original directory structure, you can set the rootdir parameter:
Os.cp ("src/**.h", "/ tmp/", {rootdir = "src"})
The above script can copy all the subfiles under the src in the directory structure by pressing the src root directory.
Note: try to use the os.cp interface instead of os.run ("cp."), which ensures platform consistency and implements cross-platform build descriptions.
Os.run
This interface silently runs native shell commands to execute third-party shell commands, but does not echo the output, but only highlights the error message after an error.
This API supports parameter formatting and built-in variables, such as:
-- format parameters are passed in
Os.run ("echo hello s!", "xmake")
-enumerate build catalog files
Os.run ("ls-l $(buildir)")
Os.execv
Compared with os.run, this API also echoes the output during execution, and the parameters are passed in through the list, which is more flexible.
Os.execv ("echo", {"hello", "xmake!"})
In addition, this interface supports an optional parameter to pass settings: redirect output and perform environment variable settings, such as:
Os.execv ("echo", {"hello", "xmake!"}, {stdout = outfile, stderr = errfile, envs = {PATH = "xxx;xx", CFLAGS = "xx", curdir = "/ tmp"}}
Where the stdout and stderr parameters are used to pass redirected output and error output, either directly to the file path or to the file object opened by io.open.
In addition, if you want to temporarily set and overwrite some environment variables during this execution, you can pass the envs parameter, which replaces the existing settings, but does not affect the outer execution environment, only the current command.
We can also get all the current environment variables through the os.getenvs () interface, then overwrite the part and pass in the envs parameter.
In addition, the working directory of the child process can be modified during execution through the curdir parameter setting.
The related interfaces include os.runv, os.exec, os.execv, os.iorun, os.iorunv and so on. For example, os.iorun can get the running output.
The details and differences of this section, as well as more os APIs, can be found in the os API documentation.
Io.readfile
This API reads all the contents from the specified path file. We can directly read the contents of the entire file without opening the file. It is more convenient, for example:
Local data = io.readfile ("xxx.txt")
Io.writefile
This API writes all the contents to the specified path file. We can directly write the contents of the entire file without opening the file, which is more convenient, for example:
Io.writefile ("xxx.txt", "all data")
Path.join
This API implements cross-platform path stitching operation, and appends multiple path items. Due to the path difference of windows/unix style, api is used to append the path more cross-platform, for example:
Print (path.join ("$(tmpdir)", "dir1", "dir2", "file.txt"))
The above stitching is equivalent to: $(tmpdir) / dir1/dir2/file.txt on unix and: $(tmpdir)\\ dir1\\ dir2\\ file.txt on windows
This is how the xmake shared by Xiaobian can be configured more flexibly through custom scripts. If you happen to have similar doubts, please refer to the above analysis to understand. If you want to know more about it, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.