In this article we’ll continue learning about Clang and how to use it in the workplace. You may want to know a little bit about compiling for iOS before you do that, check out this article.
LibTooling: LibTooling
I’m sure you’ve heard of Clang, which provides an excellent infrastructure for tools to analyze syntactic, semantic information in code. Three things were derived from this: LibClang, Clang Plugin, and LibTooling.
LibClang
LibClang provides a stable, advanced C interface, and Xcode uses LibClang. LibClang has access to Clang’s higher-level abstraction capabilities, such as fetching all tokens, traversing the syntax tree, code completion, and so on. Since the API is stable, Clang version updates have little impact on it. However, LibClang does not have full access to Clang AST information. With LibClang you can use its C API directly. Python Binding scripts are also available for you to call. There is also the open source Node-JS/Ruby Binding. If you’re not familiar with another language, there’s also a third-party open source ClangKit library written in Objective-C.
Clang Plugins
Clang Plugins allow you to do things on the AST that can be integrated into and become part of a build. Plug-ins are dynamic libraries loaded by the compiler at run time for easy integration into the build system. Clang Plugins are often used to gain full control of the Clang AST and to be integrated into the compilation process to affect the compilation process, interrupt or prompt. For a hands-on article, see this: Clang Code specification Inspection Plug-in.
LibTooling
LibTooling is a C++ interface that enables you to write a syntax verification and code refactoring tool that runs independently. LibTooling has the following advantages:
- The tools written are independent of the build system and can be used as a single command, such as clang-check, clang-fixit, and clang-format.
- Clang AST can be completely controlled.
- Being able to share code with Clang Plugins;
Compared with Clang Plugins, LibTooling does not affect the compilation process; Compared to LibClang, the LibTooling interface was less stable and did not work out of the box when the AST API was updated. However, LibTooling was able to do much more based on its ability to fully control the Clang AST and run independently. Examples include code language conversion, adherence to code specifications, analysis and even refactoring.
Following LibTooling was the developer tooling collection Clang Tools. Clang Tools, part of the Clang project, provided tools including:
- Syntax check tool clang-check;
- Clang-fixit automatically fixes compilation errors;
- Automatic code format tool clang-format;
- Migration tools for new languages and features;
- Refactoring tools;
Two, automatic burying point
LibTooling was used to implement a method that automatically NSLog the name of the method when called without affecting the original code. Automatic embedding is simply putting a piece of code in place without having to do it manually. This time we used LibTooling to add buried code where appropriate using semantic analysis of the code during compilation. Since the LibTooling itself was complete control of the Clang AST, this was theoretically ok. However, LibTooling itself did not interact with Xcode’s LibClang compilation process.
- Implement code injection with LibTooling, and save a copy of the original code.
- Xcode compilation;
- After Xcode is compiled, replace the original code back;
LibTooling development
Next, we set up a LibTooling project. The first step was to download the LLVM project.
Download and compile LLVM
Create a local folder LLVM, open the command line CD to this directory, and run the following command:
git clone https://github.com/llvm/llvm-project.git cd llvm-project mkdir build cd build cmake -G Xcode -DLLVM_ENABLE_PROJECTS=clang .. /llvmCopy the code
Among themcmake -G Xcode -DLLVM_ENABLE_PROJECTS=clang .. /llvm
The Xcode compilation project for LLVM will be generated, and you can see the following local directory:
Clang is the code directory for c-like compilers. The LLVM directory code consists of two parts, one is the optimizer code for platform-independent optimization of source code, and the other is the generator code for generating platform-dependent assembly code. The LLDB directory contains the debugger code; In LLD is linker code.
Compile the project
Next compile the LLVM project, double-click llvm. Xcodeproj and selectAutocreat Schemes
Add schemes,All_BUILD
:
Then click Running and wait for the compilation to complete, which is expected to take half an hour:
Create the LibTooling project
After compiling LLVM, create a LibTooling project named AddCodePlugin. Open theclang-tools-CMakeLists.txt
File, add a sentence at the endadd_clang_subdirectory(AddCodePlugin)
Create a new one in this directory at the same timeAddCodePlugin
Create two new files in the folder:AddCodePlugin.cpp
andCMakeLists.txt
.
In addcodeplugin-cmakelists.txt, write:
set(LLVM_LINK_COMPONENTS support)
add_clang_executable(AddCodePlugin
AddCodePlugin.cpp
)
target_link_libraries(AddCodePlugin
PRIVATE
clangAST
clangBasic
clangDriver
clangFormat
clangLex
clangParse
clangSema
clangFrontend
clangTooling
clangToolingCore
clangRewrite
clangRewriteFrontend
)
Copy the code
The addcodeplugin.cpp code was written in the following format:
int main(int argc, const char **argv) {
CommonOptionsParser op(argc, argv, AddOptionCategory);
ClangTool Tool(op.getCompilations(), op.getSourcePathList());
int result = Tool.run(newFrontendActionFactory<AddCodePlugin::ClangAutoStatsAction>().get());
return result;
}
Copy the code
I’m going to do the replacement character in handleObjcMethDecl, and I’m going to go after the curly braces of the method, and I’m going to put a little bit of code here, and what I’ve put in here is an NSLog print, so I can print out the name of the method.
bool handleObjcMethDecl(ObjCMethodDecl *MD) { if (! MD->hasBody()) return true; cout << "handleObjcMethDecl" << endl; CompoundStmt *CS = MD->getCompoundBody(); SourceLocation loc = CS->getBeginLoc().getLocWithOffset(1); if (loc.isMacroID()) { loc = rewriter.getSourceMgr().getImmediateExpansionRange(loc).getBegin(); } static std::string varName("%__FUNCNAME__%"); std::string funcName = MD->getDeclName().getAsString(); std::string codes(CodeSnippet); size_t pos = 0; // Replace the special character %__FUNCNAME__% with the method name while ((pos = codes.find(varName, pos))! = std::string::npos) { codes.replace(pos, varName.length(), funcName); pos += funcName.length(); } / / writer rewriter. InsertTextBefore (loc, codes); return true; }Copy the code
At the end of the file processing, write the changes to the file and print out the changes:
void EndSourceFileAction() { cout << "EndSourceFileAction" << endl; SourceManager &SM = fileRewriter.getSourceMgr(); std::string filename = SM.getFileEntryForID(SM.getMainFileID())->getName().str(); std::error_code error_code; llvm::raw_fd_ostream outFile(filename, error_code, llvm::sys::fs::F_None); / / the Rewriter results output to a file fileRewriter. GetEditBuffer (SM) getMainFileID ()), write (outFile); / / the Rewriter results output on the console fileRewriter. GetEditBuffer (SM) getMainFileID ()), write (LLVM: : outs ()); }Copy the code
Once you’ve done that, go back to the build folder and re-run the command:
cd build cmake -G Xcode -DLLVM_ENABLE_PROJECTS=clang .. /llvmCopy the code
Then go back to the LLVM project and compile and run Scheme:
Find the path to the AddCodePlugin executable and note it down
Run the LibTooling tool
To run the tool, write a test file called test.m:
#import <UIKit/UIKit.h> @interface HelloViewController : UIViewController - (void)sayHi; @end @implementation HelloViewController - (void)sayHi { NSLog(@"Hello world!" ); } - (void)sayHi123 { NSLog(@"Hello world!" ); } @endCopy the code
On the cli, go to the test.m folder and run the following command:
/Users/wuyanji/Desktop/LLVM/llvm-project/build/Debug/bin/AddCodePlugin test.m -- -x objective-c -arch x86_64 -std=gnu99 -fobjc-arc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk - the mios - simulator - version - min = 8.0 -F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/Syste m/Library/Frameworks -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 -I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/ includeCopy the code
Some of the following parameters are used to prevent errors such as missing the file at compile time, or you can simply enter them:
/Users/wuyanji/Desktop/LLVM/llvm-project/build/Debug/bin/AddCodePlugin test.m --
Copy the code
You can see the following results:
wuyanjideMac-mini-2:YourClang wuyanji$ /Users/wuyanji/Desktop/LLVM/llvm-project/build/Debug/bin/AddCodePlugin test.m -- -x objective-c -arch x86_64 -std=gnu99 -fobjc-arc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk - the mios - simulator - version - min = 8.0 -F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/Syste m/Library/Frameworks -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 -I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/ include handleObjcMethDecl handleObjcMethDecl EndSourceFileAction #import <UIKit/UIKit.h> @interface HelloViewController : UIViewController - (void)sayHi; @end @implementation HelloViewController - (void)sayHi {NSLog(@"sayHi"); NSLog(@"Hello world!" ); } - (void)sayHi123 {NSLog(@"sayHi123"); NSLog(@"Hello world!" ); } @endCopy the code
The method in the test.m file has added the required code block. Now that we have our tools ready, it’s time to run them with Xcode compilation.
Embed Xcode compilation
We are going to add this tool to the Xcode compilation, and we can look at the Targets-Build Phases,
Here is the order in which Xcode is compiled, where Compile Sources is the relevant file. So what we can do is we can run the tool before we compile the file and add the code, and then we can change the file back after we compile the file, and then we can compile our relevant code into our APP without modifying the file. The modified Build Phases are as follows:
The above script will copy and save a copy of the original code, and the following script will copy the original code back to the original file after compilation. Let’s try it on a file this time and see what happens. The two commands are as follows:
cp /Users/wuyanji/Documents/Build/Build/ViewController.m /Users/wuyanji/Documents/Build/Build/ViewController.m.temp /Users/wuyanji/Desktop/LLVM/llvm-project/build/Debug/bin/AddCodePlugin /Users/wuyanji/Documents/Build/Build/ViewController.m -- -x objective-c -arch $ARCHS -std=gnu99 -fobjc-arc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk - the mios - simulator - version - min = 9.0 -F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/Syste m/Library/Frameworks -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 -I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/ includeCopy the code
mv /Users/wuyanji/Documents/Build/Build/ViewController.m.temp /Users/wuyanji/Documents/Build/Build/ViewController.m
Copy the code
As expected, the name of the method is printed when the method is triggered:
Third, summary
LibTooling was one of the following tools to automatically add the print method name. LibTooling provides complete control of the compilation process. This leaves a lot of room for manipulation. There are many other features that you can implement.
code
Iv. Related articles
Clang LibTooling iOS System CLAS
Clang LibTooling iOS System CLAS
Clang LibTooling iOS System CLAS
TUTORIAL FOR BUILDING TOOLS USING LIBTOOLING AND LIBASTMATCHERS
Objective-c obfuscation method name obfuscation
How to use Clang to improve App quality?