aboutsummaryrefslogtreecommitdiff
path: root/notes/target_detection.txt
blob: 528012e56f3aa8068c3ef621efc6ab36fe3b0e66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

Detecting the OS/CPU/libc/rtld of the target
============================================

This is necessary to set the "default target" in the compiler,
so programs get compiled for the host platform by default.


Solution 1: Build a "hello world" program and analyze it
--------------------------------------------------------

1. Build the stage1 compiler as usual, using $(HOSTCC)

2. Compile a "hello world" program with $(CC) $(CFLAGS),
   instead of the $(HOSTCC) that the stage1 and stage2 compilers
   are built with.

3. Build a program with $(HOSTCC) to analyze the "hello world" program.
   The following information is needed:

   - Executable format (ELF, PE, Mach-O, a.out, etc.)
   - Format bitness (32 or 64 bit format, can be smaller
     than bitness of CPU architecture)
   - CPU architecture
   - OS / Calling convention
   - If applicable: libc.so file
   - If applicable: ELF program interpreter / RTLD

4. Write this information to a "DefaultTargetConfig.slul" file in the
   compiler source directory.

   - The stage1 compiler could just special case this class, and provide
     a dummy builtin.

5. Build the stage2 compiler (and maybe rebuilt it to produce stage3 etc.)

In order to support self-hosting also, there could be a command-line flag
to the SLUL compiler to simulate precense of the DefaultTargetConfig.slul
file if absent, with essentially copied contents from what the source/old
compiler saw. That way, the destination/new compiler would get the same
target as the old one.


Solution 2: Analyze some existing program
-----------------------------------------

Like solution 1, but try to find some existing program. However, different
systems have different commands (e.g. there's no /bin/cat on Windows), and
it also won't work with cross-compilations.


Solution 3: Never auto-detect. Require explicitly setting the target
--------------------------------------------------------------------

The target could be set via a make variable that sets a C #define.


Solution 4: Detect at runtime
-----------------------------

Could check different sources.

First, check for cross-compilation:

1. Command-line option --target=xxxx
2. TARGET environment variable.
3. CC environment variable. If set, try to detect the what kind of compiler
   it is and (gcc, clang, tcc, MSVC, etc.).
   (BUT: I don't think this really is any environment variable?
    Isn't it just a Makefile variable?)

Second, "copy" the target from the compiler executable:

4. Finding the compilers own executable image:
    - Reading auxval to find self (if somehow exposed by RTL)
    - Calling GetModuleHandle on Windows, and reading the PEB
      (don't remember exactly how this worked).
5. /proc/self, if available/mounted/allowed

Lastly, try to identify from the system:

6. Checking the environment variables might give a clue:
    - PATH starting with /   => *nix
    - PATH starting with ?:\ => Windows
    - BUT... PATH can start with `.` or something else in both cases.
      On Windows, PATH will contain `:` if it contains at least two entries.
    - WINVER on Windows?
    - SHELL on *nix
    - $_ on *nix (but on Dash, this is the name previous command,
                  while under Bash is is the full/real path!)
6. Try to read from different paths, e.g. /bin/cat, $SHELL, $_, etc.