From cbe190fa70573aefc2a1370ccaaa8f37edeab3b5 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Mon, 15 Jul 2024 00:22:10 +0800 Subject: [PATCH] cpp/llvm; os.Args; build: add llvm.BinDir to PATH --- c/clang/clang.go | 2 +- cpp/llvm/_demo/demangle/demangle.go | 34 ++++++++++++++ cpp/llvm/demangle.go | 71 +++++++++++++++++++++++++++++ cpp/llvm/llvm.go | 28 ++++++++++++ cpp/std/std.go | 2 + cpp/std/string.go | 5 ++ internal/build/build.go | 5 +- internal/lib/os/os.go | 4 -- internal/lib/os/proc.go | 65 ++++++++++++++++++++++++++ 9 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 cpp/llvm/_demo/demangle/demangle.go create mode 100644 cpp/llvm/demangle.go create mode 100644 cpp/llvm/llvm.go create mode 100644 internal/lib/os/proc.go diff --git a/c/clang/clang.go b/c/clang/clang.go index db6a617a..6a49ce27 100644 --- a/c/clang/clang.go +++ b/c/clang/clang.go @@ -172,7 +172,7 @@ func (*TranslationUnit) Cursor() (ret Cursor) { type CursorKind c.Int /* for debug/testing */ -// llgo:link (CursorKind).String C.clang_getCursorKindSpelling +// llgo:link CursorKind.String C.clang_getCursorKindSpelling func (CursorKind) String() (ret String) { return } diff --git a/cpp/llvm/_demo/demangle/demangle.go b/cpp/llvm/_demo/demangle/demangle.go new file mode 100644 index 00000000..9325c1a6 --- /dev/null +++ b/cpp/llvm/_demo/demangle/demangle.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "os" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/cpp/llvm" +) + +func Demangle(mangledName string) *c.Char { + if ret := llvm.ItaniumDemangle(mangledName, true); ret != nil { + return ret + } + if ret := llvm.RustDemangle(mangledName); ret != nil { + return ret + } + return llvm.MicrosoftDemangle(mangledName, nil, nil, 0) +} + +func main() { + if len(os.Args) != 2 { + fmt.Fprintln(os.Stderr, "Usage: demangle symbol") + return + } + mangledName := os.Args[1] + if name := Demangle(mangledName); name != nil { + c.Printf(c.Str("%s\n"), name) + c.Free(unsafe.Pointer(name)) + } else { + fmt.Fprintln(os.Stderr, "Failed to demangle") + } +} diff --git a/cpp/llvm/demangle.go b/cpp/llvm/demangle.go new file mode 100644 index 00000000..76445958 --- /dev/null +++ b/cpp/llvm/demangle.go @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package llvm + +import ( + _ "unsafe" + + "github.com/goplus/llgo/c" +) + +// ----------------------------------------------------------------------------- + +// Returns a non-NULL pointer to a NUL-terminated C style string +// that should be explicitly freed, if successful. Otherwise, may return +// nullptr if mangled_name is not a valid mangling or is nullptr. +// +// char *itaniumDemangle(std::string_view mangled_name, bool ParseParams = true); +// +//go:linkname ItaniumDemangle C._ZN4llvm15itaniumDemangleENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEEb +func ItaniumDemangle(mangledName StringView, parseParams bool) *c.Char + +/* + enum MSDemangleFlags { + MSDF_None = 0, + MSDF_DumpBackrefs = 1 << 0, + MSDF_NoAccessSpecifier = 1 << 1, + MSDF_NoCallingConvention = 1 << 2, + MSDF_NoReturnType = 1 << 3, + MSDF_NoMemberType = 1 << 4, + MSDF_NoVariableType = 1 << 5, + }; +*/ +type MSDemangleFlags c.Int + +// Demangles the Microsoft symbol pointed at by mangled_name and returns it. +// Returns a pointer to the start of a null-terminated demangled string on +// success, or nullptr on error. +// +// If n_read is non-null and demangling was successful, it receives how many +// bytes of the input string were consumed. +// +// status receives one of the demangle_ enum entries above if it's not nullptr. +// Flags controls various details of the demangled representation. +// +// char *microsoftDemangle(std::string_view mangled_name, size_t *n_read, int *status, MSDemangleFlags Flags = MSDF_None); +// +//go:linkname MicrosoftDemangle C._ZN4llvm17microsoftDemangleENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEEPmPiNS_15MSDemangleFlagsE +func MicrosoftDemangle(mangledName StringView, nRead *uintptr, status *c.Int, flags MSDemangleFlags) *c.Char + +// Demangles a Rust v0 mangled symbol. +// +// char *rustDemangle(std::string_view MangledName); +// +//go:linkname RustDemangle C._ZN4llvm12rustDemangleENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEE +func RustDemangle(mangledName StringView) *c.Char + +// ----------------------------------------------------------------------------- diff --git a/cpp/llvm/llvm.go b/cpp/llvm/llvm.go new file mode 100644 index 00000000..f43e9a93 --- /dev/null +++ b/cpp/llvm/llvm.go @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package llvm + +// ----------------------------------------------------------------------------- + +const ( + LLGoPackage = "link: -L$(llvm-config --libdir) -lLLVM; -lLLVM" +) + +// StringView represents a C++ std::string_view object. +type StringView = string + +// ----------------------------------------------------------------------------- diff --git a/cpp/std/std.go b/cpp/std/std.go index d36a2e09..9de32bff 100644 --- a/cpp/std/std.go +++ b/cpp/std/std.go @@ -16,6 +16,8 @@ package std +// ----------------------------------------------------------------------------- + const ( LLGoFiles = "_wrap/string.cpp" LLGoPackage = "link: c++" diff --git a/cpp/std/string.go b/cpp/std/string.go index fbc24bd9..fa04524f 100644 --- a/cpp/std/string.go +++ b/cpp/std/string.go @@ -25,6 +25,11 @@ import ( // ----------------------------------------------------------------------------- +// StringView represents a C++ std::string_view object. +type StringView = string + +// ----------------------------------------------------------------------------- + // String represents a C++ std::string object. type String struct { Unused [24]byte diff --git a/internal/build/build.go b/internal/build/build.go index 4cc903a0..2e27876d 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -174,7 +174,10 @@ func Do(args []string, conf *Config) { patches := make(cl.Patches, len(altPkgPaths)) altSSAPkgs(progSSA, patches, altPkgs[1:], verbose) - ctx := &context{llvm.New(""), progSSA, prog, dedup, patches, make(map[string]none), initial, mode} + env := llvm.New("") + os.Setenv("PATH", env.BinDir()+":"+os.Getenv("PATH")) // TODO(xsw): check windows + + ctx := &context{env, progSSA, prog, dedup, patches, make(map[string]none), initial, mode} pkgs := buildAllPkgs(ctx, initial, verbose) var llFiles []string diff --git a/internal/lib/os/os.go b/internal/lib/os/os.go index 0d6bf8d6..31cfb89d 100644 --- a/internal/lib/os/os.go +++ b/internal/lib/os/os.go @@ -154,10 +154,6 @@ func Environ() []string { // func Executable() (string, error) -func Exit(code int) { - os.Exit(c.Int(code)) -} - // TODO(xsw): // func Expand(s string, mapping func(string) string) string // func ExpandEnv(s string) string diff --git a/internal/lib/os/proc.go b/internal/lib/os/proc.go new file mode 100644 index 00000000..7c7adf61 --- /dev/null +++ b/internal/lib/os/proc.go @@ -0,0 +1,65 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Process etc. + +package os + +import ( + "runtime" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/os" +) + +// Args hold the command-line arguments, starting with the program name. +var Args []string + +func init() { + if runtime.GOOS == "windows" { + // TODO(xsw): check windows implementation + // Initialized in exec_windows.go. + return + } + Args = runtimeArgs(int(c.Argc), c.Argv) +} + +func runtimeArgs(argc int, argv **c.Char) []string { + args := make([]string, argc) + for i := 0; i < argc; i++ { + arg := *c.Advance(argv, i) + args[i] = unsafe.String((*byte)(unsafe.Pointer(arg)), c.Strlen(arg)) + } + return args +} + +// Getgroups returns a list of the numeric ids of groups that the caller belongs to. +// +// On Windows, it returns syscall.EWINDOWS. See the os/user package +// for a possible alternative. +func Getgroups() ([]int, error) { + /* TODO(xsw): + gids, e := syscall.Getgroups() + return gids, NewSyscallError("getgroups", e) + */ + panic("todo: os.Getgroups") +} + +// Exit causes the current program to exit with the given status code. +// Conventionally, code zero indicates success, non-zero an error. +// The program terminates immediately; deferred functions are not run. +// +// For portability, the status code should be in the range [0, 125]. +func Exit(code int) { + // Inform the runtime that os.Exit is being called. If -race is + // enabled, this will give race detector a chance to fail the + // program (racy programs do not have the right to finish + // successfully). If coverage is enabled, then this call will + // enable us to write out a coverage data file. + // TODO(xsw): + // runtime_beforeExit(code) + + os.Exit(c.Int(code)) +}