Clang: Difference between revisions

From miki
Jump to navigation Jump to search
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Links ==

=== Clang on Windows ===

==== LLVM-MinGW ====

* Get packages from https://github.com/mstorsjo/llvm-mingw

The best port of LLVM/Clang on Windows I tried.
* No dependency on Visual Studio.
* Support 32-bit and 64-bit targets.
* Support sanitizers (ASAN, UBSAN).

==== MSYS2 ====

MSYS2 now provides clang 9.0 packages.
* No dependency on Visual Studio.
* Support 32-bit and 64-bit targets.
* But {{red|'''does not'''}} support sanitizers (ASAN, UBSAN).

==== Official LLVM ====

Packages from the official LLVM at http://releases.llvm.org/download.html.

* {{red|'''DEPEND'''}} on Visual Studio for linking
* Support 32-bit and 64-bit targets.
* (Maybe) support sanitizers (ASAN, UBSAN).

== Tips ==
== Tips ==
=== Get Stack Pointer ===
=== Get Stack Pointer ===
Line 17: Line 45:
=== Enable all warnings: <code>-Weverything</code> ===
=== Enable all warnings: <code>-Weverything</code> ===
<code>-Weverything</code> means enable all current and future warnings. See [http://amattn.com/p/better_apps_clang_weverything_or_wall_is_a_lie.html Better Apps with Clang's Weverything or Wall is a Lie!]
<code>-Weverything</code> means enable all current and future warnings. See [http://amattn.com/p/better_apps_clang_weverything_or_wall_is_a_lie.html Better Apps with Clang's Weverything or Wall is a Lie!]

=== Make deterministic / reproducible builds ===
* Reference: https://blog.conan.io/2019/09/02/Deterministic-builds-with-C-C++.html

Things to look at:
* <code>__DATE__</code> and <code>__TIME__</code>. On clang, we can do <code>export ZERO_AR_DATE=1</code>.
* <code>__FILE__</code>. On clang, we can add a flag <code>-ffile-prefix-map=/some/local/build/path=.</code>.
* <code>__LINE__</code>.
* some randomness introduced by compiler: Use flag <code>-frandom-seed=0x${checksum}</code>.

Some script I used:
<source lang="bash">
ag -l __LINE__ | xargs sed -ri 's/__LINE__/1/g'
make NODEBUG=1 some.elf # Optional, but ideally build without flag -g
strip --strip-all some.elf
sha256sum some.elf
</source>

=== Get list of standard compiler defines ===
<source lang="bash">
clang -dM -E -x c /dev/null
# #define _LP64 1
# #define __ATOMIC_ACQUIRE 2
# #define __ATOMIC_ACQ_REL 4
# #define __ATOMIC_CONSUME 1
# #define __ATOMIC_RELAXED 0
</source>

=== Detect optimization levels ===
This can't detect all levels but at least some of them (from [https://stackoverflow.com/questions/31718637/determine-optimization-level-in-preprocessor SO]):

<source lang="bash">
clang -Xpreprocessor -dM -E - < /dev/null > 1
clang -Xpreprocessor -dM -O -E - < /dev/null > 2
diff 1 2
# 53a54
# > #define __OPTIMIZE__ 1
# 154d155
# < #define __NO_INLINE__ 1
</source>

== Troubleshoot ==
=== iostream not found ===
This is a funny one. Simple Hello, World program that fails with an
<source lang="c">
#include <iostream>

using namespace std;

int main() {
cout << "Hello, World" << endl;
return 0;
}
</source>

<source lang="bash">
clang++ main.cpp
# main.cpp:1:10: fatal error: 'iostream' file not found
# #include <iostream>
# ^~~~~~~~~~
# 1 error generated.
</source>

Luckily [https://stackoverflow.com/questions/54521402/locating-iostream-in-clang-fatal-error-iostream-file-not-found StackOverflow] comes to the rescue.

The problem is that we have several gcc/g++ installation, and the one selected by clang doesn't have the c++ headers.

<source lang="bash">
$ clang++ -v main.cpp
clang version 7.0.1-8 (tags/RELEASE_701/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Candidate multilib: .;@m64
Selected multilib: .;@m64
"/usr/lib/llvm-7/bin/clang" -cc1 [...]
clang -cc1 version 7.0.1 based upon LLVM 7.0.1 default target x86_64-pc-linux-gnu
ignoring nonexistent directory "/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/backward"
ignoring nonexistent directory "/include"
ignoring duplicate directory "/usr/include/clang/7.0.1/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++
/usr/include/clang/7.0.1/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
main.cpp:1:10: fatal error: 'iostream' file not found
#include <iostream>
^~~~~~~~~~
1 error generated.
</source>

The simplest for us was to uninstall gcc-9. Another solution is to install g++-9. Also it seems that clang uses some kind of prioritization, so in fact reinstalling gcc-8/g++-8 may work as well.

=== UBSAN / ASAN troubleshooting ===

;References
* https://clang.llvm.org/docs/AddressSanitizer.html
* https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html

;Build
* For ASAN:
:* Use compile and link flags <code>-fsanitize=address</code>.
:* It is also recommended to use compile flag <code>-fno-omit-frame-pointer</code> for better stack trace.

<source lang="bash">
# Compile
clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc
# Link
clang++ -g -fsanitize=address example_UseAfterFree.o
</source>

* For UBSAN:
:* Use compile and link flags <code>-fsanitize=undefined</code>.

;Troubleshoot:
* Error <code>undefined reference to typeinfo</code> when linking [https://stackoverflow.com/questions/37358573/why-does-fsanitize-undefined-cause-undefined-reference-to-typeinfo SO]
:* Fix is to flag <code>-fno-sanitize=vptr</code>.

=== No debug symbols ===
Recent version of clang uses DWARF V5. The old debug info can still be used with compile and link flag j<code>-fdebug-default-version=4</code>.

Latest revision as of 23:00, 11 May 2023

Links

Clang on Windows

LLVM-MinGW

The best port of LLVM/Clang on Windows I tried.

  • No dependency on Visual Studio.
  • Support 32-bit and 64-bit targets.
  • Support sanitizers (ASAN, UBSAN).

MSYS2

MSYS2 now provides clang 9.0 packages.

  • No dependency on Visual Studio.
  • Support 32-bit and 64-bit targets.
  • But does not support sanitizers (ASAN, UBSAN).

Official LLVM

Packages from the official LLVM at http://releases.llvm.org/download.html.

  • DEPEND on Visual Studio for linking
  • Support 32-bit and 64-bit targets.
  • (Maybe) support sanitizers (ASAN, UBSAN).

Tips

Get Stack Pointer

Use this macro [1]:

#define current_stack_pointer ({ \
        register unsigned long esp asm("esp"); \
        asm("" : "=r"(esp)); \
        esp; \
        })

Turn errors into warning

From the manual

-Wno-error=foo Turn warning “foo” into an warning even if -Werror is specified.

Enable all warnings: -Weverything

-Weverything means enable all current and future warnings. See Better Apps with Clang's Weverything or Wall is a Lie!

Make deterministic / reproducible builds

Things to look at:

  • __DATE__ and __TIME__. On clang, we can do export ZERO_AR_DATE=1.
  • __FILE__. On clang, we can add a flag -ffile-prefix-map=/some/local/build/path=..
  • __LINE__.
  • some randomness introduced by compiler: Use flag -frandom-seed=0x${checksum}.

Some script I used:

ag -l __LINE__ | xargs sed -ri 's/__LINE__/1/g'
make NODEBUG=1 some.elf                       # Optional, but ideally build without flag -g
strip --strip-all some.elf
sha256sum some.elf

Get list of standard compiler defines

clang -dM -E -x c /dev/null
# #define _LP64 1
# #define __ATOMIC_ACQUIRE 2
# #define __ATOMIC_ACQ_REL 4
# #define __ATOMIC_CONSUME 1
# #define __ATOMIC_RELAXED 0

Detect optimization levels

This can't detect all levels but at least some of them (from SO):

clang -Xpreprocessor -dM -E - < /dev/null > 1
clang -Xpreprocessor -dM -O -E - < /dev/null > 2
diff 1 2
# 53a54
# > #define __OPTIMIZE__ 1
# 154d155
# < #define __NO_INLINE__ 1

Troubleshoot

iostream not found

This is a funny one. Simple Hello, World program that fails with an

#include <iostream>

using namespace std;

int main() {
    cout << "Hello, World" << endl;
    return 0;
}
clang++ main.cpp
# main.cpp:1:10: fatal error: 'iostream' file not found
# #include <iostream>
#          ^~~~~~~~~~
# 1 error generated.

Luckily StackOverflow comes to the rescue.

The problem is that we have several gcc/g++ installation, and the one selected by clang doesn't have the c++ headers.

$ clang++ -v main.cpp
clang version 7.0.1-8 (tags/RELEASE_701/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Candidate multilib: .;@m64
Selected multilib: .;@m64
 "/usr/lib/llvm-7/bin/clang" -cc1 [...]
clang -cc1 version 7.0.1 based upon LLVM 7.0.1 default target x86_64-pc-linux-gnu
ignoring nonexistent directory "/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/backward"
ignoring nonexistent directory "/include"
ignoring duplicate directory "/usr/include/clang/7.0.1/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++
 /usr/include/clang/7.0.1/include
 /usr/local/include
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
main.cpp:1:10: fatal error: 'iostream' file not found
#include <iostream>
         ^~~~~~~~~~
1 error generated.

The simplest for us was to uninstall gcc-9. Another solution is to install g++-9. Also it seems that clang uses some kind of prioritization, so in fact reinstalling gcc-8/g++-8 may work as well.

UBSAN / ASAN troubleshooting

References
Build
  • For ASAN:
  • Use compile and link flags -fsanitize=address.
  • It is also recommended to use compile flag -fno-omit-frame-pointer for better stack trace.
# Compile
clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc
# Link
clang++ -g -fsanitize=address example_UseAfterFree.o
  • For UBSAN:
  • Use compile and link flags -fsanitize=undefined.
Troubleshoot
  • Error undefined reference to typeinfo when linking SO
  • Fix is to flag -fno-sanitize=vptr.

No debug symbols

Recent version of clang uses DWARF V5. The old debug info can still be used with compile and link flag j-fdebug-default-version=4.