{"id":109,"date":"2011-10-01T23:54:52","date_gmt":"2011-10-02T03:54:52","guid":{"rendered":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/?p=109"},"modified":"2011-11-23T01:17:45","modified_gmt":"2011-11-23T06:17:45","slug":"clang-plugin-development-tutorial","status":"publish","type":"post","link":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/2011\/10\/01\/clang-plugin-development-tutorial\/","title":{"rendered":"Clang plugin development tutorial"},"content":{"rendered":"<p>The past week I&#8217;ve had my hands deep in &#8216;build system&#8217; land.\u00a0 It&#8217;s been frustrating as hell!\u00a0 The goal was to pull down the clang source and start hacking away at a quick plugin to see what&#8217;s possible and if I can transform the code tree automagically.\u00a0 Boy was I off on the quick part.\u00a0 One problem after another trying to get things to actually build.\u00a0 Since things were so difficult for me I figured I&#8217;d share what I&#8217;ve learned in case it can help someone else.<!--more--><\/p>\n<p>There isn&#8217;t really much documentation out there specific to making clang plugins, and there&#8217;s definitely not a lot of help if things go wrong.\u00a0 One of the links I found was from the chromium <a title=\"Chromium Clang plugin\" href=\"http:\/\/code.google.com\/p\/chromium\/wiki\/WritingClangPlugins\" onclick=\"javascript:_gaq.push(['_trackEvent','outbound-article','http:\/\/code.google.com']);\" target=\"_blank\">project<\/a>. Their advice was to just copy the build system which I wasn&#8217;t happy with, and that&#8217;s what lead me down a path of pain and suffering.\u00a0 But if you&#8217;re cool with that then they&#8217;re right it might just be easier to copy the clang build system, but if you&#8217;re not cool with that then you&#8217;re in the right place.<\/p>\n<p>As prereqs here&#8217;s the things you&#8217;re likely going to want installed already to make things easier:<\/p>\n<ul>\n<li>doxygen<\/li>\n<li>graphviz<\/li>\n<li>cmake<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h3><strong>Download LLVM\/Clang<\/strong><\/h3>\n<p>To start off you&#8217;re gonna need the LLVM source tree and the clang source tree (more detail <a title=\"Clang getting started\" href=\"http:\/\/clang.llvm.org\/get_started.html\" onclick=\"javascript:_gaq.push(['_trackEvent','outbound-article','http:\/\/clang.llvm.org']);\" target=\"_blank\">here<\/a>).\u00a0 I didn&#8217;t want to go for trunk and maybe have problems beyond my understanding to begin with so I pulled down the most recent release versions instead.<\/p>\n<p>Open a shell and go do to where you want to put things.<br \/>\n<code><br \/>\nmkdir dev-lib\u00a0\u00a0\u00a0 #(\/Users\/chris\/dev-lib)<br \/>\ncd dev-lib<br \/>\nsvn co http:\/\/llvm.org\/svn\/llvm-project\/llvm\/tags\/RELEASE_29\/final llvm<br \/>\n<\/code><\/p>\n<p>Then pull down the source tree for clang.<br \/>\n<code>cd llvm\/tools<br \/>\nsvn co http:\/\/llvm.org\/svn\/llvm-project\/cfe\/branches\/release_29\/ clang<br \/>\ncd ..\/\u00a0\u00a0\u00a0\u00a0 #(back to the llvm dir)<br \/>\n<\/code><br \/>\n&nbsp;<\/p>\n<h3><strong>Build LLVM\/Clang<\/strong><\/h3>\n<p>Instead of using configure and makefiles directly I decided to play with cmake instead.\u00a0 Pretty slick if you ask me.\u00a0 And it definitely cleans up those make files.\u00a0 So I&#8217;d suggest you go the cmake route here (at least it was the way I was finally able to get things to work).<br \/>\nCreate a build directory<br \/>\n<code>mkdir build<br \/>\ncd build<br \/>\ncmake -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo ..\/<br \/>\n<\/code><\/p>\n<p>There&#8217;s a bunch of options you can pass to cmake <a title=\"Some CMake options for LLVM\" href=\"http:\/\/llvm.org\/docs\/CMake.html\" onclick=\"javascript:_gaq.push(['_trackEvent','outbound-article','http:\/\/llvm.org']);\" target=\"_blank\">here<\/a>. There&#8217;s a GUI you can use as well that will allow you to see a bunch of options (or you can run &#8220;<code>make edit-cache<\/code>&#8221; after you&#8217;ve done the initial cmake call).\u00a0 If you want to compile in the clang examples add the option &#8220;<code>-DCLANG_BUILD_EXAMPLES:BOOL=ON<\/code>&#8221;<\/p>\n<p>Now compile the llvm\/clang source. This could take a while.<br \/>\n<code>make -j3<\/code><\/p>\n<p>Since this is a development tree I didn&#8217;t want to install it on the system and have it mess with the version of clang that shipped with XCode. So I&#8217;m going to assume things are not installed and full paths are needed.<\/p>\n<p>You can now compile and test out the clang examples, like PrintFunctionNames, to make sure things work.\u00a0 The README in the example folder tells you how to do this.\u00a0 Don&#8217;t forget to use the clang version you just compiled (in build\/bin\/) rather than any others on the system.<br \/>\n&nbsp;<\/p>\n<h3><strong>Create new plugin<\/strong><\/h3>\n<p>In fact since the PrintFunctionNames is the basic plugin that we want to test out let&#8217;s pull the example into our own workspace to try and build it there.<br \/>\n<code>cd ~\/dev-lib\/<br \/>\nmkdir example<br \/>\ncd example<br \/>\nmkdir printer<br \/>\ncp ..\/llvm\/tools\/clang\/examples\/PrintfFunctionNames.cpp printer\/<br \/>\ncp ..\/llvm\/tools\/clang\/examples\/PrintfFunctionNames.exports printer\/<br \/>\n<\/code><br \/>\n&nbsp;<\/p>\n<h3><strong>Create separate build system<\/strong><\/h3>\n<p>Now we want to make this plugin separately from the llvm\/clang source tree so we&#8217;ll need to create some CMakeLists.txt for cmake to do its magic. First one is ~\/dev-lib\/example\/CMakeLists.txt<br \/>\n<code><\/p>\n<pre>\r\ncmake_minimum_required (VERSION 2.6)\r\nproject (Printer)\r\n\r\nset( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}\/bin )\r\nset( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}\/lib )\r\nset( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}\/lib )\r\n\r\nset (LLVM_SRC_DIR \/Users\/chris\/dev-lib\/llvm)\r\nset (CLANG_SRC_DIR \/Users\/chris\/dev-lib\/llvm\/tools\/clang)\r\nset (LLVM_BUILD_DIR \/Users\/chris\/dev-lib\/llvm\/build)\r\nset (CLANG_BUILD_DIR \/Users\/chris\/dev-lib\/llvm\/build\/tools\/clang)\r\n\r\nadd_definitions (-D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS)\r\nadd_definitions (-D_GNU_SOURCE -DHAVE_CLANG_CONFIG_H)\r\n\r\n# this sets up the devel clang as our compiler\r\nset (CMAKE_CXX_COMPILER \"${LLVM_BUILD_DIR}\/bin\/clang++\")\r\nset (CMAKE_CC_COMPILER \"${LLVM_BUILD_DIR}\/bin\/clang\")\r\n\r\nset (CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\r\n\t-fPIC\r\n\t-fno-common\r\n\t-Woverloaded-virtual\r\n\t-Wcast-qual\r\n\t-fno-strict-aliasing\r\n\t-pedantic\r\n\t-Wno-long-long\r\n\t-Wall\r\n\t-W\r\n\t-Wno-unused-parameter\r\n\t-Wwrite-strings\r\n\t-fno-exceptions\r\n\t-fno-rtti\")\r\nset (CMAKE_MODULE_LINKER_FLAGS \"-Wl,-flat_namespace -Wl,-undefined -Wl,suppress\")\r\n\r\nset (LLVM_LIBS\r\n\tLLVMJIT\r\n\tLLVMX86CodeGen\r\n\tLLVMX86AsmParser\r\n\tLLVMX86Disassembler\r\n\tLLVMExecutionEngine\r\n\tLLVMAsmPrinter\r\n\tLLVMSelectionDAG\r\n\tLLVMX86AsmPrinter\r\n\tLLVMX86Info\r\n\tLLVMMCParser\r\n\tLLVMCodeGen\r\n\tLLVMX86Utils\r\n\tLLVMScalarOpts\r\n\tLLVMInstCombine\r\n\tLLVMTransformUtils\r\n\tLLVMipa\r\n\tLLVMAnalysis\r\n\tLLVMTarget\r\n\tLLVMCore\r\n\tLLVMMC\r\n\tLLVMSupport\r\n)\r\n\r\nmacro(add_clang_plugin name)\r\n\tset (srcs ${ARGN})\r\n\r\n\tinclude_directories( \"${LLVM_SRC_DIR}\/include\"\r\n\t\t\"${CLANG_SRC_DIR}\/include\"\r\n\t\t\"${CLANG_BUILD_DIR}\/include\" )\r\n\tlink_directories( \"${LLVM_BUILD_DIR}\/lib\" )\r\n\r\n\tadd_library( ${name} SHARED ${srcs} )\r\n\t\r\n\tif (SYMBOL_FILE)\r\n\t\tset_target_properties( ${name} PROPERTIES LINK_FlAGS\r\n\t\t\t\"-exported_symbols_list ${SYMBOL_FILE}\")\r\n\tendif()\r\n\r\n\tforeach (clang_lib ${CLANG_LIBS})\r\n\t\ttarget_link_libraries( ${name} ${clang_lib} )\t\r\n\tendforeach()\r\n\t\r\n\tforeach (llvm_lib ${LLVM_LIBS})\r\n\t\ttarget_link_libraries( ${name} ${llvm_lib} )\r\n\tendforeach()\r\n\t\r\n\tforeach (user_lib ${USER_LIBS})\r\n\t\ttarget_link_libraries( ${name} ${user_lib} )\r\n\tendforeach()\r\n\r\nendmacro(add_clang_plugin)\r\n\r\nadd_subdirectory(printer)\r\n<\/pre>\n<p><\/code><\/p>\n<p>Notice the large list of LLVM libs to link in.\u00a0 I&#8217;m not totally sure if ALL of them need to be in the list, I just included everything to make my life easier. You should also make sure the path names for <code>LLVM_SRC_DIR<\/code> and others point to your proper paths.<\/p>\n<p>Now we have an easy macro to add any new clang plugin with.\u00a0 Just fill in a couple of variables with libraries and source files and you&#8217;re done.\u00a0 The variables you can set are <code>SYMBOL_FILE<\/code>, <code>CLANG_LIBS<\/code>, and <code>USER_LIBS<\/code>. So let&#8217;s make the CMakeLists.txt in our Printer plugin folder.<\/p>\n<p><code><\/p>\n<pre>\r\nset(SYMBOL_FILE PrintFunctionNames.exports)\r\n\r\nset (CLANG_LIBS\r\n\tclang\r\n\tclangFrontend\r\n\tclangAST\r\n\tclangAnalysis\r\n\tclangBasic\r\n\tclangCodeGen\r\n\tclangDriver\r\n\tclangFrontendTool\r\n\tclangIndex\r\n\tclangLex\r\n\tclangParse\r\n\tclangRewrite\r\n\tclangSema\r\n\tclangSerialization\r\n\tclangStaticAnalyzerCheckers\r\n\tclangStaticAnalyzerCore\r\n\tclangStaticAnalyzerFrontend\r\n)\r\n\r\nset (USER_LIBS\r\n\tpthread\r\n)\r\n\r\nadd_clang_plugin(PrintFunctionNames PrintFunctionNames.cpp)\r\n\r\nset_target_properties(PrintFunctionNames PROPERTIES\r\n\tLINKER_LANGUAGE CXX\r\n\tPREFIX \"\")\r\n<\/pre>\n<p><\/code><\/p>\n<p>We first set all the variables to pass in the proper data.<br \/>\n<code>SYMBOL_FILE<\/code> points to the symbol exports file needed to make the shared library.<br \/>\n<code>CLANG_LIBS<\/code> contains any clang libs to link with. And again, just to make my life easier I included ALL of the clang libs, whether they were needed or not.<br \/>\n<code>USER_LIBS<\/code> then contains any extra libraries you want to add, but you may need to add more link_directories if they&#8217;re not in the current search list.<br \/>\nThen we call the add_clang_plugin macro and pass it the name of the library we want made, and the name of any dependent files (*.cpp\/*.h).<br \/>\nLast, we do a couple of maintenance things on our PrintFunctionNames target so that things build the way we want them.<\/p>\n<p>That&#8217;s it for the build system! Now time to build our plugin<br \/>\n&nbsp;<\/p>\n<h3><strong>Build the plugin<\/strong><\/h3>\n<p>Create another build folder.<br \/>\n<code><br \/>\nmkdir build\u00a0\u00a0 #(\/Users\/chris\/dev-lib\/example\/build)<br \/>\ncd build<br \/>\ncmake ..\/<br \/>\nmake<br \/>\n<\/code><\/p>\n<p>You should now have a PrintFunctionNames shared library sitting in your build\/lib folder.<br \/>\n&nbsp;<\/p>\n<h3><strong>Test the plugin<\/strong><\/h3>\n<p>Let&#8217;s test it out. (I&#8217;m using bash here)<br \/>\n<code><br \/>\nexport TEMP_CXX_FLAGS=\"-D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -I..\/..\/llvm\/include -I..\/..\/llvm\/tools\/clang\/include -I..\/..\/llvm\/build\/tools\/clang\/include\"<br \/>\n..\/..\/llvm\/build\/bin\/clang -cc1 -load lib\/PrintFunctionNames.dylib ${TEMP_CXX_FLAGS} -plugin print-fns ..\/printer\/PrintFunctionNames.cpp<br \/>\n<\/code><\/p>\n<p>If everything went right, there should be a ton of function names on your screen<br \/>\n&nbsp;<\/p>\n<h3><strong>Profit!&#8230;<\/strong><\/h3>\n<p>So that&#8217;s it. There&#8217;s your first clang plugin. Hopefully this helps someone get started.<\/p>\n<p>My next goal is to test things out a bit and build up something to create an automatic RTTI system. Still a long ways away from that though, but I&#8217;ll be sure to let you know how it goes.<\/p>\n<p>Be sure to add me on twitter @<a title=\"GOMLE_ca\" href=\"http:\/\/twitter.com\/#!\/GOMLE_ca\" onclick=\"javascript:_gaq.push(['_trackEvent','outbound-article','http:\/\/twitter.com']);\" target=\"_blank\">GOMLE_ca<\/a> and let me know if you come up with any cool plugins if your own.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The past week I&#8217;ve had my hands deep in &#8216;build system&#8217; land.\u00a0 It&#8217;s been frustrating as hell!\u00a0 The goal was to pull down the clang source and start hacking away at a quick plugin to see what&#8217;s possible and if I can transform the code tree automagically.\u00a0 Boy was I off on the quick part.\u00a0 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-109","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/posts\/109","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/comments?post=109"}],"version-history":[{"count":18,"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/posts\/109\/revisions"}],"predecessor-version":[{"id":137,"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/posts\/109\/revisions\/137"}],"wp:attachment":[{"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/media?parent=109"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/categories?post=109"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/GetOffMyLawnEntertainment.com\/blog\/wp-json\/wp\/v2\/tags?post=109"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}