diff --git a/chore/nmdump/nmdump.go b/chore/nmdump/nmdump.go index f9b46d58..cdb36554 100644 --- a/chore/nmdump/nmdump.go +++ b/chore/nmdump/nmdump.go @@ -30,7 +30,7 @@ func main() { return } - nm := llvm.New().Nm() + nm := llvm.New("").Nm() items, err := nm.List(os.Args[1]) for _, item := range items { if item.File != "" { diff --git a/chore/nmindex/nmindex.go b/chore/nmindex/nmindex.go index e8f9f254..43d34118 100644 --- a/chore/nmindex/nmindex.go +++ b/chore/nmindex/nmindex.go @@ -54,7 +54,7 @@ The commands are: } func makeIndex() { - env := llvm.New() + env := llvm.New("") idxDir := indexDir() os.MkdirAll(idxDir, 0755) diff --git a/internal/build/build.go b/internal/build/build.go index de0b52c0..050a2cd3 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -37,8 +37,8 @@ import ( "github.com/goplus/llgo/cl" "github.com/goplus/llgo/internal/packages" "github.com/goplus/llgo/ssa/abi" - "github.com/goplus/llgo/xtool/clang" "github.com/goplus/llgo/xtool/env" + "github.com/goplus/llgo/xtool/env/llvm" llssa "github.com/goplus/llgo/ssa" clangCheck "github.com/goplus/llgo/xtool/clang/check" @@ -308,21 +308,29 @@ func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, llFiles []string, conf if app == "" { app = filepath.Join(conf.BinPath, name+conf.AppExt) } - const N = 6 - args := make([]string, N, len(pkg.Imports)+len(llFiles)+(N+1)) - args[0] = "-o" - args[1] = app - args[2] = "-Wno-override-module" - args[3] = "-Xlinker" - if runtime.GOOS == "darwin" { // ld64.lld (macOS) - args[4] = "-dead_strip" - args[5] = "" // It's ok to leave it empty, as we can assume libpthread is built-in on macOS. - } else { // ld.lld (Unix), lld-link (Windows), wasm-ld (WebAssembly) - args[4] = "--gc-sections" - args[5] = "-lpthread" // libpthread is built-in since glibc 2.34 (2021-08-01); we need to support earlier versions. + args := make([]string, 0, len(pkg.Imports)+len(llFiles)+10) + args = append( + args, + "-o", app, + "-fuse-ld=lld", + "-Wno-override-module", + // "-O2", // FIXME: This will cause TestFinalizer in _test/bdwgc.go to fail on macOS. + ) + switch runtime.GOOS { + case "darwin": // ld64.lld (macOS) + args = append( + args, + "-Xlinker", "-dead_strip", + ) + case "windows": // lld-link (Windows) + // TODO: Add options for Windows. + default: // ld.lld (Unix), wasm-ld (WebAssembly) + args = append( + args, + "-Xlinker", "--gc-sections", + "-lpthread", // libpthread is built-in since glibc 2.34 (2021-08-01); we need to support earlier versions. + ) } - //args[6] = "-fuse-ld=lld" // TODO(xsw): to check lld exists or not - //args[7] = "-O2" needRuntime := false needPyInit := false packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) { @@ -378,7 +386,7 @@ func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, llFiles []string, conf if verbose { fmt.Fprintln(os.Stderr, "clang", args) } - err := clang.New("").Exec(args...) + err := llvm.New("").Clang().Exec(args...) check(err) switch mode { @@ -646,7 +654,7 @@ func clFile(cFile, expFile string, procFile func(linkFile string), verbose bool) if verbose { fmt.Fprintln(os.Stderr, "clang", args) } - err := clang.New("").Exec(args...) + err := llvm.New("").Clang().Exec(args...) check(err) procFile(llFile) } diff --git a/xtool/env/env.go b/xtool/env/env.go index 803bdd3e..87beba9d 100644 --- a/xtool/env/env.go +++ b/xtool/env/env.go @@ -1,3 +1,19 @@ +/* + * 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 env import ( diff --git a/xtool/env/llvm/llvm.go b/xtool/env/llvm/llvm.go index cb5343ca..06fc35c1 100644 --- a/xtool/env/llvm/llvm.go +++ b/xtool/env/llvm/llvm.go @@ -18,28 +18,73 @@ package llvm import ( "os" + "os/exec" + "path/filepath" + "strings" + "github.com/goplus/llgo/xtool/clang" + "github.com/goplus/llgo/xtool/llvm/llvmlink" "github.com/goplus/llgo/xtool/nm" ) -type Env struct { - root string - nmprefix string -} +// ----------------------------------------------------------------------------- -func New() *Env { - var nmprefix string - var root = os.Getenv("LLGO_LLVM_ROOT") - if root != "" { - nmprefix = root + "/bin/llvm-" +// defaultLLVMConfigBin returns the default path to the llvm-config binary. It +// checks the LLVM_CONFIG environment variable first, then searches in PATH. If +// not found, it returns [ldLLVMConfigBin] as a last resort. +func defaultLLVMConfigBin() string { + bin := os.Getenv("LLVM_CONFIG") + if bin != "" { + return bin } - return &Env{root, nmprefix} + bin, _ = exec.LookPath("llvm-config") + if bin != "" { + return bin + } + return ldLLVMConfigBin } -func (p *Env) Root() string { - return p.root +// ----------------------------------------------------------------------------- + +// Env represents an LLVM installation. +type Env struct { + binDir string } -func (p *Env) Nm() *nm.Cmd { - return nm.New(p.nmprefix + "nm") +// New creates a new [Env] instance. +func New(llvmConfigBin string) *Env { + if llvmConfigBin == "" { + llvmConfigBin = defaultLLVMConfigBin() + } + + // Note that an empty binDir is acceptable. In this case, LLVM + // executables are assumed to be in PATH. + binDir, _ := exec.Command(llvmConfigBin, "--bindir").Output() + + e := &Env{binDir: strings.TrimSpace(string(binDir))} + return e } + +// BinDir returns the directory containing LLVM executables. An empty string +// means LLVM executables are assumed to be in PATH. +func (e *Env) BinDir() string { return e.binDir } + +// Clang returns a new [clang.Cmd] instance. +func (e *Env) Clang() *clang.Cmd { + bin := filepath.Join(e.BinDir(), "clang") + return clang.New(bin) +} + +// Link returns a new [llvmlink.Cmd] instance. +func (e *Env) Link() *llvmlink.Cmd { + bin := filepath.Join(e.BinDir(), "llvm-link") + return llvmlink.New(bin) +} + +// Nm returns a new [nm.Cmd] instance. +func (e *Env) Nm() *nm.Cmd { + bin := filepath.Join(e.BinDir(), "llvm-nm") + return nm.New(bin) +} + +// ----------------------------------------------------------------------------- diff --git a/xtool/env/llvm/llvm_config_byollvm.go b/xtool/env/llvm/llvm_config_byollvm.go new file mode 100644 index 00000000..54aeedd3 --- /dev/null +++ b/xtool/env/llvm/llvm_config_byollvm.go @@ -0,0 +1,26 @@ +//go:build byollvm + +/* + * 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. + */ + +// The word "byollvm" stands for "Bring Your Own LLVM" and is a build tag used +// to indicate that the package is being built with a custom LLVM installation. + +package llvm + +// ldLLVMConfigBin is the path to the llvm-config binary. It shoud be set via +// -ldflags when building the package. +var ldLLVMConfigBin string diff --git a/xtool/env/llvm/llvm_config_darwin_amd64_llvm14.go b/xtool/env/llvm/llvm_config_darwin_amd64_llvm14.go new file mode 100644 index 00000000..0fd03691 --- /dev/null +++ b/xtool/env/llvm/llvm_config_darwin_amd64_llvm14.go @@ -0,0 +1,21 @@ +//go:build !byollvm && darwin && amd64 && llvm14 + +/* + * 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 ldLLVMConfigBin = "/usr/local/opt/llvm@14/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_darwin_amd64_llvm15.go b/xtool/env/llvm/llvm_config_darwin_amd64_llvm15.go new file mode 100644 index 00000000..1d4d04a1 --- /dev/null +++ b/xtool/env/llvm/llvm_config_darwin_amd64_llvm15.go @@ -0,0 +1,21 @@ +//go:build !byollvm && darwin && amd64 && llvm15 + +/* + * 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 ldLLVMConfigBin = "/usr/local/opt/llvm@15/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_darwin_amd64_llvm16.go b/xtool/env/llvm/llvm_config_darwin_amd64_llvm16.go new file mode 100644 index 00000000..7dc84ec0 --- /dev/null +++ b/xtool/env/llvm/llvm_config_darwin_amd64_llvm16.go @@ -0,0 +1,21 @@ +//go:build !byollvm && darwin && amd64 && llvm16 + +/* + * 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 ldLLVMConfigBin = "/usr/local/opt/llvm@16/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_darwin_amd64_llvm17.go b/xtool/env/llvm/llvm_config_darwin_amd64_llvm17.go new file mode 100644 index 00000000..84096511 --- /dev/null +++ b/xtool/env/llvm/llvm_config_darwin_amd64_llvm17.go @@ -0,0 +1,21 @@ +//go:build !byollvm && darwin && amd64 && !llvm14 && !llvm15 && !llvm16 + +/* + * 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 ldLLVMConfigBin = "/usr/local/opt/llvm@17/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_darwin_llvm14.go b/xtool/env/llvm/llvm_config_darwin_llvm14.go new file mode 100644 index 00000000..ac271e53 --- /dev/null +++ b/xtool/env/llvm/llvm_config_darwin_llvm14.go @@ -0,0 +1,21 @@ +//go:build !byollvm && darwin && !amd64 && llvm14 + +/* + * 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 ldLLVMConfigBin = "/opt/homebrew/opt/llvm@14/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_darwin_llvm15.go b/xtool/env/llvm/llvm_config_darwin_llvm15.go new file mode 100644 index 00000000..a0df2cad --- /dev/null +++ b/xtool/env/llvm/llvm_config_darwin_llvm15.go @@ -0,0 +1,21 @@ +//go:build !byollvm && darwin && !amd64 && llvm15 + +/* + * 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 ldLLVMConfigBin = "/opt/homebrew/opt/llvm@15/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_darwin_llvm16.go b/xtool/env/llvm/llvm_config_darwin_llvm16.go new file mode 100644 index 00000000..bdb91b5f --- /dev/null +++ b/xtool/env/llvm/llvm_config_darwin_llvm16.go @@ -0,0 +1,21 @@ +//go:build !byollvm && darwin && !amd64 && llvm16 + +/* + * 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 ldLLVMConfigBin = "/opt/homebrew/opt/llvm@16/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_darwin_llvm17.go b/xtool/env/llvm/llvm_config_darwin_llvm17.go new file mode 100644 index 00000000..b9597045 --- /dev/null +++ b/xtool/env/llvm/llvm_config_darwin_llvm17.go @@ -0,0 +1,21 @@ +//go:build !byollvm && darwin && !amd64 && !llvm14 && !llvm15 && !llvm16 + +/* + * 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 ldLLVMConfigBin = "/opt/homebrew/opt/llvm@17/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_linux_llvm14.go b/xtool/env/llvm/llvm_config_linux_llvm14.go new file mode 100644 index 00000000..8c0330f2 --- /dev/null +++ b/xtool/env/llvm/llvm_config_linux_llvm14.go @@ -0,0 +1,21 @@ +//go:build !byollvm && linux && llvm14 + +/* + * 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 ldLLVMConfigBin = "/usr/lib/llvm-14/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_linux_llvm15.go b/xtool/env/llvm/llvm_config_linux_llvm15.go new file mode 100644 index 00000000..9e29d745 --- /dev/null +++ b/xtool/env/llvm/llvm_config_linux_llvm15.go @@ -0,0 +1,21 @@ +//go:build !byollvm && linux && llvm15 + +/* + * 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 ldLLVMConfigBin = "/usr/lib/llvm-15/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_linux_llvm16.go b/xtool/env/llvm/llvm_config_linux_llvm16.go new file mode 100644 index 00000000..71abb184 --- /dev/null +++ b/xtool/env/llvm/llvm_config_linux_llvm16.go @@ -0,0 +1,21 @@ +//go:build !byollvm && linux && llvm16 + +/* + * 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 ldLLVMConfigBin = "/usr/lib/llvm-16/bin/llvm-config" diff --git a/xtool/env/llvm/llvm_config_linux_llvm17.go b/xtool/env/llvm/llvm_config_linux_llvm17.go new file mode 100644 index 00000000..0982e764 --- /dev/null +++ b/xtool/env/llvm/llvm_config_linux_llvm17.go @@ -0,0 +1,21 @@ +//go:build !byollvm && linux && !llvm14 && !llvm15 && !llvm16 + +/* + * 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 ldLLVMConfigBin = "/usr/lib/llvm-17/bin/llvm-config" diff --git a/xtool/llvm/llvmlink/link.go b/xtool/llvm/llvmlink/link.go index 3079affa..b52f3c4c 100644 --- a/xtool/llvm/llvmlink/link.go +++ b/xtool/llvm/llvmlink/link.go @@ -35,7 +35,7 @@ type Cmd struct { // New creates a new llvm-link command. func New(app string) *Cmd { if app == "" { - app = os.Getenv("LLGO_LLVM_ROOT") + "/bin/llvm-link" + app = "llvm-link" } return &Cmd{app, os.Stdout, os.Stderr} }