diff options
author | Ayke van Laethem <[email protected]> | 2023-10-13 16:12:34 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2023-10-14 11:35:26 +0200 |
commit | d801d0cd539447322228e9f1daa860774584b4d3 (patch) | |
tree | a1a608bd558051b19f05cb2114585489f4cefae9 /goenv/goenv.go | |
parent | c2f1965e0358d3f044bd8f8282ce3942d669ff89 (diff) | |
download | tinygo-d801d0cd539447322228e9f1daa860774584b4d3.tar.gz tinygo-d801d0cd539447322228e9f1daa860774584b4d3.zip |
builder: refactor clang include headers
Set -resource-dir in a central place instead of passing the header path
around everywhere and adding it using the `-I` flag. I believe this is
closer to how Clang is intended to be used.
This change was inspired by my attempt to add a Nix flake file to
TinyGo.
Diffstat (limited to 'goenv/goenv.go')
-rw-r--r-- | goenv/goenv.go | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/goenv/goenv.go b/goenv/goenv.go index f6a32502a..5e2a3753b 100644 --- a/goenv/goenv.go +++ b/goenv/goenv.go @@ -14,6 +14,8 @@ import ( "runtime" "strings" "sync" + + "tinygo.org/x/go-llvm" ) // Keys is a slice of all available environment variable keys. @@ -33,6 +35,9 @@ func init() { } } +// Set to true if we're linking statically against LLVM. +var hasBuiltinTools = false + // TINYGOROOT is the path to the final location for checking tinygo files. If // unset (by a -X ldflag), then sourceDir() will fallback to the original build // directory. @@ -284,3 +289,70 @@ func isSourceDir(root string) bool { _, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go")) return err == nil } + +// ClangResourceDir returns the clang resource dir if available. This is the +// -resource-dir flag. If it isn't available, an empty string is returned and +// -resource-dir should be left unset. +// The libclang flag must be set if the resource dir is read for use by +// libclang. +// In that case, the resource dir is always returned (even when linking +// dynamically against LLVM) because libclang always needs this directory. +func ClangResourceDir(libclang bool) string { + if !hasBuiltinTools && !libclang { + // Using external tools, so the resource dir doesn't need to be + // specified. Clang knows where to find it. + return "" + } + + // Check whether we're running from a TinyGo release directory. + // This is the case for release binaries on GitHub. + root := Get("TINYGOROOT") + releaseHeaderDir := filepath.Join(root, "lib", "clang") + if _, err := os.Stat(releaseHeaderDir); !errors.Is(err, fs.ErrNotExist) { + return releaseHeaderDir + } + + if hasBuiltinTools { + // We are statically linked to LLVM. + // Check whether we're running from the source directory. + // This typically happens when TinyGo was built using `make` as part of + // development. + llvmMajor := strings.Split(llvm.Version, ".")[0] + buildResourceDir := filepath.Join(root, "llvm-build", "lib", "clang", llvmMajor) + if _, err := os.Stat(buildResourceDir); !errors.Is(err, fs.ErrNotExist) { + return buildResourceDir + } + } else { + // We use external tools, either when installed using `go install` or + // when packaged in a Linux distribution (Linux distros typically prefer + // dynamic linking). + // Try to detect the system clang resources directory. + resourceDir := findSystemClangResources(root) + if resourceDir != "" { + return resourceDir + } + } + + // Resource directory not found. + return "" +} + +// Find the Clang resource dir on this particular system. +// Return the empty string when they aren't found. +func findSystemClangResources(TINYGOROOT string) string { + llvmMajor := strings.Split(llvm.Version, ".")[0] + + switch runtime.GOOS { + case "linux", "android": + // Header files are typically stored in /usr/lib/clang/<version>/include. + // Tested on Fedora 39, Debian 12, and Arch Linux. + path := filepath.Join("/usr/lib/clang", llvmMajor) + _, err := os.Stat(filepath.Join(path, "include", "stdint.h")) + if err == nil { + return path + } + } + + // Could not find it. + return "" +} |