Add Windows build with clang
This commit is contained in:
4
namecollision/.gitignore
vendored
4
namecollision/.gitignore
vendored
@@ -1,2 +1,6 @@
|
||||
libhello.so
|
||||
libhello.dll
|
||||
libhello.lib
|
||||
main
|
||||
main.exe
|
||||
libhello.exp
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
`print_obj()`. `main.cpp` defines a `namespace nt` with a free function
|
||||
`print()`, and calls both `nt::print()` and `print_obj()`.
|
||||
|
||||
`hello.cpp` is compiled into a shared library (`libhello.so`), and `main.cpp` is
|
||||
linked against it.
|
||||
`hello.cpp` is compiled into a shared library (`libhello.so` on Linux,
|
||||
`libhello.dll` on Windows), and `main.cpp` is linked against it.
|
||||
|
||||
## The Problem
|
||||
|
||||
@@ -80,7 +80,34 @@ This flat namespace behavior means a weak symbol in a `.so` can be silently
|
||||
overridden by any strong symbol of the same name anywhere in the process — even
|
||||
from the main executable.
|
||||
|
||||
## The Fix
|
||||
## Why Windows Is Not Affected
|
||||
|
||||
On Windows, this collision does not occur. The DLL symbol model is fundamentally
|
||||
different:
|
||||
|
||||
- Only symbols explicitly marked `__declspec(dllexport)` are visible outside the
|
||||
DLL — everything else is private by default
|
||||
- The linker generates an import library (`.lib`) with stubs that reference the
|
||||
DLL by name, so the loader knows exactly which DLL each symbol comes from
|
||||
- There is no flat global symbol namespace — each DLL is its own isolated scope
|
||||
|
||||
This means the internal `class nt` in `hello.cpp` was never at risk on Windows
|
||||
regardless of optimization level. The bug is Linux (and ELF) specific.
|
||||
|
||||
To keep `hello.cpp` portable, the `__declspec(dllexport)` on `print_obj` is
|
||||
wrapped in a macro:
|
||||
|
||||
```cpp
|
||||
#ifdef _WIN32
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
```
|
||||
|
||||
On Linux `EXPORT` expands to nothing. On Windows it marks the symbol for export.
|
||||
|
||||
## The Linux Fix
|
||||
|
||||
Wrap internal-use classes in an **anonymous namespace** in `hello.cpp`:
|
||||
|
||||
@@ -103,6 +130,10 @@ The `_GLOBAL__N_1` prefix is the ABI encoding for the anonymous namespace,
|
||||
making it unique per translation unit and invisible to the dynamic linker. No
|
||||
collision is possible.
|
||||
|
||||
The Linux and Windows fixes solve the same problem from opposite defaults:
|
||||
- Linux: **opt-in to hiding** symbols (anonymous namespace, `-fvisibility=hidden`)
|
||||
- Windows: **opt-in to exporting** symbols (`__declspec(dllexport)`)
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
- Class and namespace names mangle identically in the Itanium C++ ABI
|
||||
@@ -110,7 +141,9 @@ collision is possible.
|
||||
the executable
|
||||
- ODR violations are UB with no required diagnostic — bugs may only appear at
|
||||
certain optimization levels
|
||||
- This is a Linux/ELF-specific problem — Windows DLLs use explicit export tables
|
||||
and are not affected
|
||||
- Internal implementation details in shared libraries should use anonymous
|
||||
namespaces to prevent symbol leakage
|
||||
namespaces to prevent symbol leakage on Linux
|
||||
- Use `objdump -t` or `nm` to inspect symbol visibility and catch these issues
|
||||
early
|
||||
|
||||
15
namecollision/build.ps1
Normal file
15
namecollision/build.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
param(
|
||||
[string]$Opt = "-O0"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Compile hello.cpp as a shared library (also generates libhello.lib import library)
|
||||
clang++ -std=c++17 $Opt -shared -o libhello.dll hello.cpp "-Wl,/IMPLIB:libhello.lib"
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
|
||||
# Compile and link main.cpp with the shared library
|
||||
clang++ -std=c++17 $Opt -o main.exe main.cpp libhello.lib
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
|
||||
Write-Host "Build successful"
|
||||
@@ -1,5 +1,11 @@
|
||||
#include <iostream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
class nt {
|
||||
@@ -9,7 +15,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void print_obj() {
|
||||
EXPORT void print_obj() {
|
||||
cout << "Hello from function\n";
|
||||
nt obj;
|
||||
obj.print();
|
||||
|
||||
Reference in New Issue
Block a user