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.

  1. Implement code injection with LibTooling, and save a copy of the original code.
  2. Xcode compilation;
  3. 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 .. /llvmThe 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 SchemesAdd 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.txtFile, add a sentence at the endadd_clang_subdirectory(AddCodePlugin)

Create a new one in this directory at the same timeAddCodePluginCreate two new files in the folder:AddCodePlugin.cppandCMakeLists.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?