<br><br><div class="gmail_quote">On Sat Dec 20 2014 at 12:26:08 PM Ivan Koster <<a href="mailto:ivankoster@gmail.com">ivankoster@gmail.com</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hello all,<div><br></div><div>I want to create a tool that facilitates easy test seam injection in legacy C code.</div><div>The reason for this is many colleagues (including myself) finding it very tedious and maintenance intensive to create stubs / mocks for our legacy C code base. This causes us to write less unittests than we want to. We currently use a routing mechanism with #defines in a .h file that reroutes functions to stubs/mocks and is included when we compile for unittesting.</div><div><br></div><div>I have been researching several ways of creating test seams, and have settled on a method which leverages function pointers. A welcome help was the article at <a href="http://meekrosoft.wordpress.com/2012/07/20/test-seams-in-c-function-pointers-vs-preprocessor-hash-defines-vs-link-time-substitution/" target="_blank">http://meekrosoft.wordpress.com/2012/07/20/test-seams-in-c-function-pointers-vs-preprocessor-hash-defines-vs-link-time-substitution/</a></div><div>But to make it truly easy, I need the compiler to do it for me. This is were clang/llvm comes in.</div><div><br></div><div>What I want is the following. Given the following 2 files:</div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div>// interface.h</div></div><div><div>__attribute__((easy_test_seam))</div></div><div><div>int foo(void);</div></div><div><div><br></div></div><div><div>// implementation.c</div></div><div><div>int foo(void)</div></div><div><div>{</div></div><div><div>    return 2;</div></div><div><div>}</div></div></blockquote><div><br></div><div>I actually want it to be compiled as:</div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div>// interface.h</div></div><div><div>extern int (*foo)(void);</div></div><div><div><br></div></div><div><div>// implementation.c</div></div><div><div>int foo_orig(void)</div></div><div><div>{</div></div><div><div>    return 2;</div></div><div><div>}</div></div><div><div>int (*foo)(void) = foo_orig;</div></div></blockquote><div><br></div><div>In a later stage we could also add standard stub generation, maybe an attribute like:</div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>__attribute__((easy_test_seam(5)))</div><div>int foo(void);</div></blockquote><div>Which would also create a standard stub that returns 5;<br></div><div><br></div><div>I see this method as a huge relief. It's maintenance friendly, we only have to add the attribute to the legacy interfaces. We will only act on the attribute if we compile for unittesting. Since we then won't have changed production code it also won't mess up static analysis of production code and won't fool IDE's jump to definition functionality.</div><div><br></div><div>The last few days I have been researching how to do this.</div><div><br></div><div>I have seen many suggest source-to-source transformation using the clang Rewriter class. This is not my preferred choice, I don't have the need to edit the *.c and *.h files, I just want them compiled differently. I would also have to extend our build system to clone my *.c and *.h files, run them through the source-to-source transform tool, and then compile the resulting .c and .h files. This is not insurmountable, but not trivial either.</div></div></blockquote><div><br></div><div>It is pretty much the same as editing the AST directly. You can do all the source editing in memory in a single tool, *and* do the compile step on the changed source from the same tool; no need to write anything to disk (in fact, the rewriting tools all have the source in memory before they edit the files on disk).</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><br></div><div>I've seen some suggestions against changing the clang AST, because it's supposed to be immutable and is hard.</div><div><br></div><div>I've also seen some suggestions to do LLVM IR transform passes, but I haven't dived deep enough in LLVM IR to determine if this can work or not.</div><div><br></div><div>I'm very new to clang and LLVM, can you guys help me determine which of the three ways would be the way to go? Or maybe there is another way?</div><div><br></div><div>Thanks in advance!</div><div><br></div><div>Regards,</div><div><br></div><div>Ivan</div><div><br></div><div><br></div></div>
______________________________<u></u>_________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@cs.uiuc.edu" target="_blank">cfe-dev@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev" target="_blank">http://lists.cs.uiuc.edu/<u></u>mailman/listinfo/cfe-dev</a><br>
</blockquote></div>