Skip to content

Commit d7a7eec

Browse files
committed
Use builder by default and fail if unsupported platform
1 parent fecb52b commit d7a7eec

File tree

5 files changed

+112
-36
lines changed

5 files changed

+112
-36
lines changed

build/env/env.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os/exec"
77
"path/filepath"
88
"strings"
9+
"sync"
910

1011
"github.com/oasisprotocol/cli/cmd/common"
1112
)
@@ -86,6 +87,10 @@ type ContainerEnv struct {
8687
}
8788

8889
var containerCmds = []string{"docker", "podman"}
90+
var (
91+
containerCmdPath string
92+
containerCmdOnce sync.Once
93+
)
8994

9095
// NewContainerEnv creates a new Docker or Podman-based execution environment.
9196
func NewContainerEnv(image, baseDir, dirMount string) *ContainerEnv {
@@ -213,12 +218,20 @@ func (de *ContainerEnv) HasBinary(string) bool {
213218

214219
// getContainerCmd finds a working docker or podman command and returns its path.
215220
func getContainerCmd() string {
216-
for _, cmd := range containerCmds {
217-
if path, err := exec.LookPath(cmd); err == nil && path != "" {
218-
return path
221+
containerCmdOnce.Do(func() {
222+
for _, cmd := range containerCmds {
223+
if path, err := exec.LookPath(cmd); err == nil && path != "" {
224+
containerCmdPath = path
225+
return
226+
}
219227
}
220-
}
221-
return ""
228+
})
229+
return containerCmdPath
230+
}
231+
232+
// IsContainerRuntimeAvailable returns true if a container runtime (docker or podman) is available.
233+
func IsContainerRuntimeAvailable() bool {
234+
return getContainerCmd() != ""
222235
}
223236

224237
// IsAvailable implements ExecEnv.

build/rofl/artifacts.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package rofl
22

3+
// DefaultBuilderImage is the default builder container image to use when building ROFL apps.
4+
const DefaultBuilderImage = "ghcr.io/oasisprotocol/rofl-dev:v0.5.0@sha256:31573686552abeb0edebc450f6872831f0006a6cf38220cef7e0789d4376c2c1"
5+
36
// LatestBasicArtifacts are the latest TDX ROFL basic app artifacts.
47
var LatestBasicArtifacts = ArtifactsConfig{
58
Firmware: "https://github.com/oasisprotocol/oasis-boot/releases/download/v0.6.2/ovmf.tdx.fd#db47100a7d6a0c1f6983be224137c3f8d7cb09b63bb1c7a5ee7829d8e994a42f",

build/sgxs/sgxs.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import (
1515
// It requires the `ftxsgx-elf2sgxs` utility to be installed.
1616
func Elf2Sgxs(buildEnv env.ExecEnv, elfSgxPath, sgxsPath string, heapSize, stackSize, threads uint64) (err error) {
1717
if elfSgxPath, err = buildEnv.PathToEnv(elfSgxPath); err != nil {
18-
return
18+
return err
1919
}
2020
if sgxsPath, err = buildEnv.PathToEnv(sgxsPath); err != nil {
21-
return
21+
return err
2222
}
2323

2424
args := []string{
@@ -31,7 +31,7 @@ func Elf2Sgxs(buildEnv env.ExecEnv, elfSgxPath, sgxsPath string, heapSize, stack
3131

3232
cmd := exec.Command("ftxsgx-elf2sgxs", args...)
3333
if err = buildEnv.WrapCommand(cmd); err != nil {
34-
return
34+
return err
3535
}
3636
if common.IsVerbose() {
3737
fmt.Println(cmd)

cmd/rofl/build/build.go

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import (
77
"maps"
88
"os"
99
"os/exec"
10+
"runtime"
1011
"slices"
12+
"strings"
1113

1214
"github.com/spf13/cobra"
1315
flag "github.com/spf13/pflag"
@@ -88,41 +90,56 @@ var (
8890
// Ensure deterministic umask for builds.
8991
setUmask(0o002)
9092

93+
// Determine builder image to use.
94+
builderImage := ""
95+
if manifest.Artifacts != nil {
96+
builderImage = strings.TrimSpace(manifest.Artifacts.Builder)
97+
if manifest.Artifacts.Builder != "" && builderImage == "" {
98+
return fmt.Errorf("builder image is empty after trimming whitespace")
99+
}
100+
}
101+
102+
// Determine if we need to use a container for building.
103+
// Native builds are only supported on Linux. On other platforms, we require
104+
// a container.
105+
nativeBuildSupported := runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
106+
containerAvailable := env.IsContainerRuntimeAvailable()
107+
91108
var buildEnv env.ExecEnv
92109
switch {
93-
case manifest.Artifacts == nil || manifest.Artifacts.Builder == "" || noContainer:
110+
case noContainer:
111+
if !nativeBuildSupported {
112+
return fmt.Errorf("native ROFL builds are only supported on linux/amd64; remove --no-container to use containerized builds on %s/%s", runtime.GOOS, runtime.GOARCH)
113+
}
114+
// Force native build regardless of manifest.
94115
buildEnv = env.NewNativeEnv()
95116
default:
96-
var baseDir string
97-
baseDir, err = env.GetBasedir()
98-
if err != nil {
99-
return fmt.Errorf("failed to determine base directory: %w", err)
117+
useContainer := false
118+
if !nativeBuildSupported {
119+
useContainer = true
120+
} else if builderImage != "" {
121+
useContainer = true
100122
}
101123

102-
containerEnv := env.NewContainerEnv(
103-
manifest.Artifacts.Builder,
104-
baseDir,
105-
"/src",
106-
)
107-
containerEnv.AddDirectory(tmpDir)
108-
buildEnv = containerEnv
109-
110-
if buildEnv.IsAvailable() {
111-
fmt.Printf("Initializing build environment...\n")
112-
// Run a dummy command to make sure that all necessary Docker layers
113-
// for the build environment are downloaded at the start instead of
114-
// later in the build process.
115-
// Also pipe all output from the process to stdout/stderr, so the user
116-
// can follow the progress in real-time.
117-
cmd := exec.Command("true")
118-
cmd.Stdout = os.Stdout
119-
cmd.Stderr = os.Stderr
120-
if err = buildEnv.WrapCommand(cmd); err != nil {
121-
return fmt.Errorf("unable to wrap command: %w", err)
122-
}
123-
if err = cmd.Run(); err != nil {
124-
return fmt.Errorf("failed to initialize build environment: %w", err)
124+
if !useContainer {
125+
buildEnv = env.NewNativeEnv()
126+
break
127+
}
128+
129+
if !containerAvailable {
130+
if builderImage != "" {
131+
return fmt.Errorf("builder specified in manifest but no container runtime (docker or podman) is available")
125132
}
133+
return fmt.Errorf("native ROFL builds are only supported on linux/amd64; on %s/%s you need docker or podman installed", runtime.GOOS, runtime.GOARCH)
134+
}
135+
136+
if builderImage == "" {
137+
builderImage = buildRofl.DefaultBuilderImage
138+
}
139+
fmt.Printf("Using container build environment (image: %s)\n", builderImage)
140+
buildEnv, err = setupContainerEnv(builderImage, tmpDir)
141+
if err != nil {
142+
return err
126143
}
127144
}
128145

@@ -304,6 +321,39 @@ var (
304321
}
305322
)
306323

324+
// setupContainerEnv creates and initializes a container build environment.
325+
func setupContainerEnv(builderImage, tmpDir string) (env.ExecEnv, error) {
326+
baseDir, err := env.GetBasedir()
327+
if err != nil {
328+
return nil, fmt.Errorf("failed to determine base directory: %w", err)
329+
}
330+
331+
containerEnv := env.NewContainerEnv(
332+
builderImage,
333+
baseDir,
334+
"/src",
335+
)
336+
containerEnv.AddDirectory(tmpDir)
337+
338+
fmt.Printf("Initializing build environment...\n")
339+
// Run a dummy command to make sure that all necessary Docker layers
340+
// for the build environment are downloaded at the start instead of
341+
// later in the build process.
342+
// Also pipe all output from the process to stdout/stderr, so the user
343+
// can follow the progress in real-time.
344+
cmd := exec.Command("true")
345+
cmd.Stdout = os.Stdout
346+
cmd.Stderr = os.Stderr
347+
if err = containerEnv.WrapCommand(cmd); err != nil {
348+
return nil, fmt.Errorf("unable to wrap command: %w", err)
349+
}
350+
if err = cmd.Run(); err != nil {
351+
return nil, fmt.Errorf("failed to initialize build environment with image %s (ensure the image is accessible and your container runtime can pull it): %w", builderImage, err)
352+
}
353+
354+
return containerEnv, nil
355+
}
356+
307357
func setupBuildEnv(deployment *buildRofl.Deployment, npa *common.NPASelection) {
308358
// Configure app ID.
309359
os.Setenv("ROFL_APP_ID", deployment.AppID)

docs/rofl.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ Building ROFL apps does not require a working TEE on your machine. However, you
9898
do need to install all corresponding tools. Check out the [ROFL Prerequisites]
9999
chapter for details.
100100

101+
Platform/container selection rules:
102+
103+
- On Linux/amd64, builds are native by default unless the manifest specifies a
104+
`builder` image; you can force native builds with `--no-container` even if a
105+
`builder` is set.
106+
- On macOS/Windows/other architectures, builds always use a containerized
107+
builder; `--no-container` will fail on these platforms.
108+
- If a containerized build is selected (due to platform or manifest), Docker or
109+
Podman must be available; otherwise the build fails.
110+
101111
:::
102112

103113
[ROFL Prerequisites]: https://github.com/oasisprotocol/oasis-sdk/blob/main/docs/rofl/workflow/prerequisites.md

0 commit comments

Comments
 (0)