Skip to content
Draft
100 changes: 99 additions & 1 deletion v3/internal/commands/build_assets/linux/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,40 @@ tasks:
cmds:
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
vars:
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
BUILD_FLAGS: >-
{{ if eq .STATIC "true" }}
-tags production -trimpath -buildvcs=false -ldflags="-w -s -linkmode external -extldflags '-static'"
{{ else if eq .PRODUCTION "true" }}
-tags production -trimpath -buildvcs=false -ldflags="-w -s"
{{ else }}
-buildvcs=false -gcflags=all="-l"
{{ end }}
env:
Comment on lines +21 to 22

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

YAML syntax error – quoting breaks the Taskfile

yamllint flags line 21. Single quotes can’t contain back-slash-escaped single quotes. Switch the outer quotes to double quotes or double the inner single quotes.

-      BUILD_FLAGS: '{{if eq .STATIC "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -linkmode external -extldflags '\''-static'\''"{{else if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
+      BUILD_FLAGS: "{{- if eq .STATIC \"true\" -}}-tags production -trimpath -buildvcs=false -ldflags='-w -s -linkmode external -extldflags \"-static\"'{{- else if eq .PRODUCTION \"true\" -}}-tags production -trimpath -buildvcs=false -ldflags='-w -s'{{- else -}}-buildvcs=false -gcflags=all=\"-l\"{{- end -}}"

Replicate the same quoting fix for the CC env on line 27 and for the build:static task (line 42).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
BUILD_FLAGS: '{{if eq .STATIC "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -linkmode external -extldflags '\''-static'\''"{{else if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
env:
BUILD_FLAGS: "{{- if eq .STATIC \"true\" -}}-tags production -trimpath -buildvcs=false -ldflags='-w -s -linkmode external -extldflags \"-static\"'{{- else if eq .PRODUCTION \"true\" -}}-tags production -trimpath -buildvcs=false -ldflags='-w -s'{{- else -}}-buildvcs=false -gcflags=all=\"-l\"{{- end -}}"
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 21-21: syntax error: expected , but found ''

(syntax)

🤖 Prompt for AI Agents
In v3/internal/commands/build_assets/linux/Taskfile.yml around lines 21-22, the
YAML syntax is broken due to improper quoting where single quotes contain
backslash-escaped single quotes. Fix this by changing the outer quotes on line
21 from single to double quotes or by doubling the inner single quotes to
properly escape them. Apply the same quoting correction to the CC environment
variable on line 27 and the build:static task on line 42 to ensure consistent
and valid YAML syntax.

Comment thread
leaanthony marked this conversation as resolved.
GOOS: linux
CGO_ENABLED: 1
GOARCH: '{{.ARCH | default ARCH}}'
PRODUCTION: '{{.PRODUCTION | default "false"}}'
CC: '{{if eq .STATIC "true"}}{{.CC | default "musl-gcc"}}{{else}}{{.CC | default ""}}{{end}}'

Comment thread
leaanthony marked this conversation as resolved.
Outdated
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
build:static:
summary: Builds a statically linked application for Linux using musl
deps:
- task: common:go:mod:tidy
- task: common:build:frontend
vars:
BUILD_FLAGS:
ref: .BUILD_FLAGS
PRODUCTION: "true"
- task: common:generate:icons
cmds:
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}-static
vars:
BUILD_FLAGS: '-tags production -trimpath -buildvcs=false -ldflags="-w -s -linkmode external -extldflags '\''-static'\''"'
env:
GOOS: linux
CGO_ENABLED: 1
GOARCH: '{{.ARCH | default ARCH}}'
CC: '{{.CC | default "musl-gcc"}}'

Comment thread
coderabbitai[bot] marked this conversation as resolved.
package:
summary: Packages a production build of the application for Linux
Expand All @@ -37,6 +65,16 @@ tasks:
- task: create:rpm
- task: create:aur

package:static:
summary: Packages a statically linked build of the application for Linux
deps:
- task: build:static
cmds:
- task: create:appimage:static
- task: create:deb:static
- task: create:rpm:static
- task: create:aur:static

create:appimage:
summary: Creates an AppImage
dir: build/linux/appimage
Expand Down Expand Up @@ -117,3 +155,63 @@ tasks:
run:
cmds:
- '{{.BIN_DIR}}/{{.APP_NAME}}'

run:static:
cmds:
- '{{.BIN_DIR}}/{{.APP_NAME}}-static'

create:appimage:static:
summary: Creates a static AppImage
dir: build/linux/appimage
deps:
- task: build:static
- task: generate:dotdesktop
cmds:
- cp {{.APP_BINARY}} {{.APP_NAME}}
- cp ../../appicon.png appicon.png
- wails3 generate appimage -binary {{.APP_NAME}} -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/linux/appimage/build
vars:
APP_NAME: '{{.APP_NAME}}-static'
APP_BINARY: '../../../bin/{{.APP_NAME}}-static'
ICON: '../../appicon.png'
DESKTOP_FILE: '../{{.APP_NAME}}.desktop'
OUTPUT_DIR: '../../../bin'

Comment thread
coderabbitai[bot] marked this conversation as resolved.
create:deb:static:
summary: Creates a static deb package
deps:
- task: build:static
cmds:
- task: generate:dotdesktop
- task: generate:deb:static

create:rpm:static:
summary: Creates a static rpm package
deps:
- task: build:static
cmds:
- task: generate:dotdesktop
- task: generate:rpm:static

create:aur:static:
summary: Creates a static arch linux package
deps:
- task: build:static
cmds:
- task: generate:dotdesktop
- task: generate:aur:static

generate:deb:static:
summary: Creates a static deb package
cmds:
- wails3 tool package -name {{.APP_NAME}}-static -format deb -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin

generate:rpm:static:
summary: Creates a static rpm package
cmds:
- wails3 tool package -name {{.APP_NAME}}-static -format rpm -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin

generate:aur:static:
summary: Creates a static arch linux package
cmds:
- wails3 tool package -name {{.APP_NAME}}-static -format archlinux -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin
38 changes: 34 additions & 4 deletions v3/internal/commands/task_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,42 @@ import (
"github.com/wailsapp/wails/v3/internal/flags"
)

func Build(_ *flags.Build) error {
return wrapTask("build")
func Build(options *flags.Build) error {
taskName := "build"

// If static flag is enabled, use the static build task
if options.Static {
taskName = "build:static"
}

// Set up environment variables for the task
if options.Static {
os.Setenv("STATIC", "true")
}
if options.Compiler != "" {
os.Setenv("CC", options.Compiler)
}
Comment on lines +22 to +24

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Unset CC when not explicitly provided

Once CC is exported it remains for the lifetime of the process, which can surprise later builds/tests executed in-process. Mirror the pattern above:

 	if options.Compiler != "" {
 		os.Setenv("CC", options.Compiler)
+	} else {
+		_ = os.Unsetenv("CC")
 	}

Also applies to: 41-43

🤖 Prompt for AI Agents
In v3/internal/commands/task_wrapper.go at lines 22-24 and 41-43, the
environment variable "CC" is set when options.Compiler is provided but not unset
when it is empty. To fix this, add an else clause to unset "CC" using
os.Unsetenv("CC") when options.Compiler is an empty string, ensuring the
environment variable does not persist unexpectedly for later builds or tests.


return wrapTask(taskName)
Comment on lines +18 to +26

@coderabbitai coderabbitai Bot Jun 11, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Environment variables linger between successive calls

os.Setenv("STATIC", "true") is only executed when options.Static is true.
If the calling process later invokes a non-static build in the same run, STATIC will still be set to "true", unintentionally forcing a static build.

-	if options.Static {
-		os.Setenv("STATIC", "true")
-	}
+	if options.Static {
+		os.Setenv("STATIC", "true")
+	} else {
+		_ = os.Unsetenv("STATIC")
+	}

Apply the same pattern for CC.
Alternatively, build an env map and pass it only to RunTask, avoiding global mutations altogether.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Set up environment variables for the task
if options.Static {
os.Setenv("STATIC", "true")
}
if options.Compiler != "" {
os.Setenv("CC", options.Compiler)
}
return wrapTask(taskName)
// Set up environment variables for the task
if options.Static {
os.Setenv("STATIC", "true")
} else {
_ = os.Unsetenv("STATIC")
}
if options.Compiler != "" {
os.Setenv("CC", options.Compiler)
}
return wrapTask(taskName)
🤖 Prompt for AI Agents
In v3/internal/commands/task_wrapper.go around lines 18 to 26, environment
variables STATIC and CC are set globally using os.Setenv without clearing them
when options.Static is false or options.Compiler is empty, causing lingering
effects between calls. To fix this, explicitly unset or clear the STATIC and CC
environment variables when their corresponding options are not set, or better,
avoid global mutations by constructing a local environment map with the needed
variables and pass it directly to the task execution function instead of using
os.Setenv.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that true though? The cli will have exited and been restarted. Aren't environment variables only active for the duration of the process?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@leaanthony
You’re right—those environment-variable mutations only live for the lifetime of the current process. Each time the user runs wails3 build … or wails3 package …, a brand-new process is started, so anything we put into os.Setenv disappears as soon as the command finishes.

The only time the “lingering” could bite us is if, inside one single process, we called both commands.Build() and commands.Package() (or another Build()) with different flag sets. Today that never happens: the cobra CLI instantiates one command handler, returns, and the binary exits.

So the extra os.Unsetenv(...) isn’t strictly necessary for correctness. That said, adding it is harmless and makes the intent explicit—if a future refactor ever re-uses the same process for multiple tasks, we’re protected. Either approach is acceptable; feel free to keep the code as-is if you prefer the simpler version.

}

func Package(_ *flags.Package) error {
return wrapTask("package")
func Package(options *flags.Package) error {
taskName := "package"

// If static flag is enabled, use the static package task
if options.Static {
taskName = "package:static"
}

// Set up environment variables for the task
if options.Static {
os.Setenv("STATIC", "true")
}
if options.Compiler != "" {
os.Setenv("CC", options.Compiler)
}

return wrapTask(taskName)
}

func wrapTask(command string) error {
Expand Down
4 changes: 4 additions & 0 deletions v3/internal/doctor/packagemanager/apt.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func (a *Apt) Packages() Packagemap {
"npm": []*Package{
{Name: "npm", SystemPackage: true},
},
"musl-dev": []*Package{
{Name: "musl-dev", SystemPackage: true, Optional: true},
{Name: "musl-tools", SystemPackage: true, Optional: true},
},
}
}

Expand Down
4 changes: 4 additions & 0 deletions v3/internal/doctor/packagemanager/dnf.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func (y *Dnf) Packages() Packagemap {
{Name: "npm", SystemPackage: true},
{Name: "nodejs-npm", SystemPackage: true},
},
"musl-dev": []*Package{
{Name: "musl-devel", SystemPackage: true, Optional: true},
{Name: "musl-gcc", SystemPackage: true, Optional: true},
},
}
}

Expand Down
3 changes: 3 additions & 0 deletions v3/internal/doctor/packagemanager/emerge.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func (e *Emerge) Packages() Packagemap {
"npm": []*Package{
{Name: "net-libs/nodejs", SystemPackage: true},
},
"musl-dev": []*Package{
{Name: "sys-libs/musl", SystemPackage: true, Optional: true},
},
}
}

Expand Down
3 changes: 3 additions & 0 deletions v3/internal/doctor/packagemanager/pacman.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func (p *Pacman) Packages() Packagemap {
"npm": []*Package{
{Name: "npm", SystemPackage: true},
},
"musl-dev": []*Package{
{Name: "musl", SystemPackage: true, Optional: true},
},
}
}

Expand Down
3 changes: 3 additions & 0 deletions v3/internal/doctor/packagemanager/zypper.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ func (z *Zypper) Packages() Packagemap {
"npm": []*Package{
{Name: "npm10", SystemPackage: true},
},
"musl-dev": []*Package{
{Name: "musl-devel", SystemPackage: true, Optional: true},
},
}
}

Expand Down
4 changes: 4 additions & 0 deletions v3/internal/flags/task_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package flags

type Build struct {
Common
Static bool `name:"static" description:"Enable static linking using musl-gcc (Linux only)"`
Compiler string `name:"cc" description:"C compiler to use for compilation"`
}

type Dev struct {
Expand All @@ -10,4 +12,6 @@ type Dev struct {

type Package struct {
Common
Static bool `name:"static" description:"Enable static linking using musl-gcc (Linux only)"`
Compiler string `name:"cc" description:"C compiler to use for compilation"`
}
Loading