Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add linker to the cli #24

Merged
merged 4 commits into from
Aug 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: |
cd ..
git clone https://github.com/llvm/llvm-project llvm
git clone --depth 1 --branch llvmorg-12.0.1 https://github.com/llvm/llvm-project llvm
mkdir ./llvm/build
cd ./llvm/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -G "Unix Makefiles" ../llvm
Expand All @@ -43,7 +43,7 @@ jobs:
run: |
mkdir ./lib
cd ./lib
git clone https://github.com/antlr/antlr4.git
git clone --depth 1 https://github.com/antlr/antlr4.git

#- name: Build
# env:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
- name: Setup LLVM - Configure
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: | #-DLLVM_ENABLE_EH=ON -DLLVM_ENABLE_RTTI=ON
git clone https://github.com/llvm/llvm-project llvm
git clone --depth 1 --branch llvmorg-12.0.1 https://github.com/llvm/llvm-project llvm
./dockcross cmake -B./llvm/build -H./llvm/llvm -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2"

- name: Setup LLVM - Build
Expand All @@ -53,7 +53,7 @@ jobs:
run: |
mkdir -p ./compiler/lib
cd ./compiler/lib
git clone https://github.com/antlr/antlr4.git
git clone --depth 1 https://github.com/antlr/antlr4.git

- name: Configure & compile project
run: ./dockcross -a "-e LLVM_DIR=/work/llvm/build/lib/cmake/llvm" sh -c "sudo mkdir -p /usr/share/man/man1 && sudo apt-get update -y && sudo apt-get install --ignore-missing --no-install-recommends --yes libc6-i386 openjdk-11-jre uuid-dev && cmake -Bbin -H./compiler -GNinja && ninja -Cbin"
Expand Down
2 changes: 2 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ nfpms:
- apk
- deb
- rpm
dependencies:
- build-essential
contents:
- src: bin/spicec-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}/*
dst: /usr/lib/spice/
Expand Down
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ ENV SPICE_DOCKERIZED=1

ARG COMPILER_PATH=linux-amd64

RUN apk update && apk add --no-cache libc6-compat libstdc++ && rm -rf /var/cache/apk/*
RUN apk update && apk add --no-cache libc6-compat libstdc++ libncurses5 && rm -rf /var/cache/apk/*
RUN ln -s /lib64/ld-linux-x86-64.so.2 /lib/ld-linux-x86-64.so.2

COPY spice /usr/bin/spice
COPY bin/spicec-${COMPILER_PATH}/ /usr/lib/spice/
Expand Down
31 changes: 25 additions & 6 deletions cli/cmd/build.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,38 @@
package cmd

import (
"os"
"path/filepath"
"runtime"
"spice/internal"
"strings"
)

// Build takes the passed code file, resolves its dependencies and emits an executable, representing its functionality
func Build(sourceFile string, targetTriple string, outputPath string, debugOutput bool) {
sourceFileName := filepath.Base(sourceFile)
sourceFileNameWithoutExt := strings.TrimSuffix(sourceFileName, filepath.Ext(sourceFileName))

// Get temp dir as location for object files
tmpDir := os.TempDir()
objectPath := tmpDir + "/spice-output.o"

// Compile program ane emit object file to temp dir
internal.Compile(sourceFile, targetTriple, objectPath, debugOutput)

// Set default value for outputPath
if outputPath == "" {
outputPath = "./output.o"
} else if !strings.HasSuffix(outputPath, ".o") {
outputPath += ".o"
if runtime.GOOS == "windows" {
if outputPath == "" {
outputPath = ".\\" + sourceFileNameWithoutExt + ".exe"
} else if !strings.HasSuffix(outputPath, ".exe") {
outputPath += ".exe"
}
} else if runtime.GOOS == "linux" {
if outputPath == "" {
outputPath = "./" + sourceFileNameWithoutExt
}
}

// Compile program ane emit executable to output file
internal.Compile(sourceFile, targetTriple, outputPath, debugOutput)
// Run g++ with output file
internal.Link(objectPath, outputPath)
}
25 changes: 24 additions & 1 deletion cli/cmd/install.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
package cmd

import (
"os"
"path/filepath"
"runtime"
"strings"
)

// Install takes the passed code file, resolves its dependencies, emits an executable and installs it to a directory in the system PATH
func Install(sourceFile string, debugOutput bool) {
// Compile program and emit executable to local bin dir
sourceFileName := filepath.Base(sourceFile)
sourceFileNameWithoutExt := strings.TrimSuffix(sourceFileName, filepath.Ext(sourceFileName))

// Get path to install to
installDir := "./"
installPath := installDir + sourceFileNameWithoutExt
if runtime.GOOS == "windows" {
installDir = os.Getenv("USERPROFILE") + "\\spice\\bin\\"
os.MkdirAll(installDir, 0755)
installPath = installDir + "\\" + sourceFileNameWithoutExt + ".exe"
} else if runtime.GOOS == "linux" {
installDir = "/usr/local/bin"
os.MkdirAll(installDir, 0755)
installPath = installDir + "/" + sourceFileNameWithoutExt
}

// Build executable to the install path
Build(sourceFile, "", installPath, debugOutput)
}
30 changes: 25 additions & 5 deletions cli/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,36 @@ package cmd

import (
"os"
"spice/internal"
"os/exec"
"path/filepath"
"runtime"
"strings"
)

// Run takes the passed code file, resolves its dependencies, emits an executable and runs it
func Run(sourceFile string) {
sourceFileName := filepath.Base(sourceFile)
sourceFileNameWithoutExt := strings.TrimSuffix(sourceFileName, filepath.Ext(sourceFileName))

// Get path to build to
buildPath := "./" + sourceFileNameWithoutExt
if runtime.GOOS == "windows" {
buildPath = os.TempDir()
os.MkdirAll(buildPath, 0755)
buildPath += "\\spice-executable.exe"
} else if runtime.GOOS == "linux" {
buildPath = os.TempDir()
os.MkdirAll(buildPath, 0755)
buildPath += "/spice-executable"
}

// Compile program and emit executable file to tmp dir
tmpPath := os.TempDir()
println(tmpPath)
internal.Compile(sourceFile, "", tmpPath+"/spice-output.o", false)
Build(sourceFile, "", buildPath, false)

// Run executable

cmd := exec.Command(buildPath)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
cmd.Wait()
}
24 changes: 24 additions & 0 deletions cli/internal/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,30 @@ func Compile(sourceFile string, targetTriple string, outputPath string, debugOut
}
}

// Link bundles the object files which were created by the compiler to an output executable
func Link(sourceFile string, outputFile string) {
// Search for g++
gccPath := "g++"
if !CommandExists(gccPath) {
util.Error("g++ executable not found. Please make sure you have the package 'build-essential', containing the g++ executable installed", true)
}

// Execute g++
cmd := exec.Command(gccPath, "-no-pie", "-o", outputFile, sourceFile)
output, err := cmd.CombinedOutput()
if err != nil {
if exiterr, ok := err.(*exec.ExitError); ok {
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
util.Pel()
util.Pel()
util.Error("Linker exited with status code "+strconv.Itoa(status.ExitStatus())+"\nFailed to link: "+string(output), true)
}
} else {
util.Error("Failed to call linker executable", true)
}
}
}

// CommandExists checks if the stated command exists on the host system
func CommandExists(cmd string) bool {
_, err := safeexec.LookPath(cmd)
Expand Down
4 changes: 2 additions & 2 deletions cli/spice.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func main() {
installCommand := cli.Command{
Name: "install",
Aliases: []string{"i"},
Usage: "Builds your Spice program, installs it and adds it to the path env variable",
Usage: "Builds your Spice program and installs it to a directory in the PATH variable",
Flags: []cli.Flag{
&cli.PathFlag{Name: "debug-output", Aliases: []string{"d"}, Usage: "Print compiler output for debugging"},
},
Expand All @@ -55,7 +55,7 @@ func main() {
runCommand := cli.Command{
Name: "run",
Aliases: []string{"r"},
Usage: "Builds your Spice program and runs it",
Usage: "Builds your Spice program and runs it immediately",
Flags: []cli.Flag{
&cli.PathFlag{Name: "debug-output", Aliases: []string{"d"}, Usage: "Print compiler output for debugging"},
},
Expand Down
5 changes: 4 additions & 1 deletion wix.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
"spicec.exe"
]
},
"directories": [
"[%USERPROFILE]spice\\bin"
],
"env": {
"guid": "27bebd64-9bda-4b0f-b7ca-5bfc26b06cdb",
"vars": [
{
"name": "PATH",
"value": "[INSTALLDIR]",
"value": "[INSTALLDIR];%USERPROFILE%\\spice\\bin",
"permanent": "yes",
"system": "no",
"action": "set",
Expand Down