{"id":497,"date":"2019-04-25T12:45:32","date_gmt":"2019-04-25T16:45:32","guid":{"rendered":"http:\/\/blog.mozilla.org\/nfroyd\/?p=497"},"modified":"2019-04-25T12:45:32","modified_gmt":"2019-04-25T16:45:32","slug":"an-unexpected-benefit-of-standardizing-on-clang-cl","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/nfroyd\/2019\/04\/25\/an-unexpected-benefit-of-standardizing-on-clang-cl\/","title":{"rendered":"an unexpected benefit of standardizing on clang-cl"},"content":{"rendered":"<p>I wrote several months ago <a href=\"http:\/\/blog.mozilla.org\/nfroyd\/2018\/05\/29\/when-implementation-monoculture-right-thing\/\">about our impending decision to switch to clang-cl on Windows<\/a>.\u00a0 In the intervening months, we did that, and we also <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1512504\">dropped MSVC as a supported compiler<\/a>.\u00a0 (We still build on Linux with GCC, and will probably continue to do that for some time.)\u00a0 One (extremely welcome) consequence of the switch to clang-cl has only become clear to me in the past couple of weeks: using assembly language across platforms is no longer painful.<\/p>\n<p>First, a little bit of background: GCC (and Clang) support <a href=\"https:\/\/gcc.gnu.org\/onlinedocs\/gcc\/Using-Assembly-Language-with-C.html\">a feature called inline assembly<\/a>, which enables you to write little snippets of assembly code directly in your C\/C++ program.\u00a0 The syntax is baroque, it&#8217;s incredibly easy to shoot yourself in the foot with it, and it&#8217;s incredibly useful for a variety of low-level things.\u00a0 <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/assembler\/inline\/inline-assembler\">MSVC supports inline assembly<\/a> as well, but only on x86, and with a completely different syntax than GCC.<\/p>\n<p>OK, so maybe you want to put your code in a separate assembly file instead.\u00a0 The complementary assembler for GCC (courtesy of <a href=\"http:\/\/sourceware.org\/binutils\/\">binutils<\/a>) is called <code>gas<\/code>, with its own specific syntax for various low-level details.\u00a0 If you give <code>gcc<\/code> an assembly file, it knows to pass it directly to <code>gas<\/code>, and <a href=\"https:\/\/gcc.gnu.org\/onlinedocs\/gcc\/Overall-Options.htm\">will even run the C preprocessor on the assembly<\/a> before invoking <code>gas<\/code> if you request that.\u00a0 So you only ever need to invoke <code>gcc<\/code> to compile everything, and the right thing will just happen. MSVC, by contrast, requires you to invoke a separate, differently-named assembler for each architecture, with different assembly language syntaxes (e.g. directives for the x86-64 assembler are quite different than the arm64 assembler), and preprocessing files beforehand requires you to jump through hoops.\u00a0 (To be fair, a number of these details are handled for you if you&#8217;re building from inside Visual Studio; the differences are only annoying to handle in cross-platform build systems.)<\/p>\n<p>In short, dealing with assembler in a world where you have to support MSVC is somewhat painful.\u00a0 You have to <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1480549\">copy-and-paste code<\/a>, or maybe you write <a href=\"https:\/\/github.com\/libav\/gas-preprocessor\">Perl scripts to translate from the gas syntax<\/a> to whatever flavor of syntax the Microsoft assembler you&#8217;re using is.\u00a0 Your build system needs to handle Windows and non-Windows differently for assembly files, and may even need to handle different architectures for Windows differently.\u00a0 Things like our ICU data generation <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/d143f8ce30d1bcfee7a1227c27bf876a85f8cede\/config\/external\/icu\/data\/moz.build#25-39\">have been made somewhat more complex than necessary<\/a> to support Windows platforms.<\/p>\n<p>Enter clang-cl.\u00a0 Since clang-cl is just clang under the hood, it handles being passed assembly files on the command line in the same way and will even preprocess them for you.\u00a0 Additionally, clang-cl contains <a href=\"https:\/\/github.com\/llvm-mirror\/llvm\/tree\/master\/lib\/MC\/MCParser\">a gas-compatible assembly syntax parser<\/a>, so assembly files that you pass on the command line are parsed by clang-cl and therefore you can now write a single assembly syntax that works on Unix-y and Windows platforms.\u00a0 (You do, of course, have to handle differing platform calling conventions and the like, but that&#8217;s simplified by having a preprocessor available all the time.)\u00a0 Finally, clang-cl supports GCC-style inline assembly, so you don&#8217;t <a href=\"https:\/\/phabricator.services.mozilla.com\/D28758\">even have to drop into separate assembly files<\/a> if you don&#8217;t want to.<\/p>\n<p>In short, clang-cl solves every problem that made assembly usage painful on Windows. Might we have a future world where open source projects that have to deal with any amount of assembly standardize on clang-cl for their Windows support, and declare MSVC unsupported?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote several months ago about our impending decision to switch to clang-cl on Windows.\u00a0 In the intervening months, we did that, and we also dropped MSVC as a supported compiler.\u00a0 (We still build on Linux with GCC, and will probably continue to do that for some time.)\u00a0 One (extremely welcome) consequence of the switch [&hellip;]<\/p>\n","protected":false},"author":320,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[19457,72456,5],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts\/497"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/users\/320"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/comments?post=497"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts\/497\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/media?parent=497"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/categories?post=497"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/tags?post=497"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}