diff --git a/compileopts/target.go b/compileopts/target.go index 16d21f46c..29b3733bd 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -24,6 +24,7 @@ import ( // https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json type TargetSpec struct { Inherits []string `json:"inherits,omitempty"` + InheritableOnly bool `json:"inheritable-only"` // this target is only meant to be inherited from, not used directly Triple string `json:"llvm-target,omitempty"` CPU string `json:"cpu,omitempty"` ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag @@ -148,6 +149,11 @@ func (spec *TargetSpec) loadFromGivenStr(str string) error { // resolveInherits loads inherited targets, recursively. func (spec *TargetSpec) resolveInherits() error { + // Save InheritableOnly before resolving, since it must not propagate + // from parent to child (a board target should not become inheritable-only + // just because its parent processor target is). + inheritableOnly := spec.InheritableOnly + // First create a new spec with all the inherited properties. newSpec := &TargetSpec{} for _, name := range spec.Inherits { @@ -173,6 +179,9 @@ func (spec *TargetSpec) resolveInherits() error { } *spec = *newSpec + // Restore InheritableOnly from the original spec, not from parents. + spec.InheritableOnly = inheritableOnly + return nil } @@ -239,10 +248,17 @@ func GetTargetSpecs() (map[string]*TargetSpec, error) { continue } path := filepath.Join(dir, entry.Name()) + spec, err := LoadTarget(&Options{Target: path}) if err != nil { return nil, fmt.Errorf("could not list target: %w", err) } + + if spec.InheritableOnly { + // Skip targets that are only meant to be inherited from, not used directly. + continue + } + if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" { // This doesn't look like a regular target file, but rather like // a parent target (such as targets/cortex-m.json). diff --git a/compileopts/target_test.go b/compileopts/target_test.go index 579c54f67..d8a17a5e3 100644 --- a/compileopts/target_test.go +++ b/compileopts/target_test.go @@ -23,6 +23,37 @@ func TestLoadTarget(t *testing.T) { } } +func TestGetTargetSpecs_InheritableOnlyTargetsExcluded(t *testing.T) { + specs, err := GetTargetSpecs() + if err != nil { + t.Fatal("GetTargetSpecs failed:", err) + } + + // Inheritable-only processor-level targets should not appear in the listing. + inheritableOnlyTargets := []string{"esp32", "esp32c3", "esp32s3", "esp8266", "rp2040", "rp2350", "rp2350b"} + for _, name := range inheritableOnlyTargets { + if _, ok := specs[name]; ok { + t.Errorf("inheritable-only target %q should not appear in GetTargetSpecs", name) + } + } + + // Board targets that inherit from inheritable-only targets should still appear. + boardTargets := []string{"esp32-coreboard-v2", "pico"} + for _, name := range boardTargets { + if _, ok := specs[name]; !ok { + t.Errorf("board target %q should appear in GetTargetSpecs", name) + } + } +} + +func TestLoadTarget_InheritableOnlyTargetStillLoadable(t *testing.T) { + // Inheritable-only targets should still be loadable directly (for building). + _, err := LoadTarget(&Options{Target: "esp32"}) + if err != nil { + t.Errorf("LoadTarget should still load inheritable-only target esp32: %v", err) + } +} + func TestOverrideProperties(t *testing.T) { baseAutoStackSize := true base := &TargetSpec{ diff --git a/main.go b/main.go index 5316798a1..a798b9fb4 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,8 @@ import ( "go.bug.st/serial/enumerator" ) +var errInheritableOnly = errors.New("target is inheritable-only, which means it cannot be used directly for building or flashing") + // commandError is an error type to wrap os/exec.Command errors. This provides // some more information regarding what went wrong while running a command. type commandError struct { @@ -140,6 +142,10 @@ func printCommand(cmd string, args ...string) { // Build compiles and links the given package and writes it to outpath. func Build(pkgName, outpath string, config *compileopts.Config) error { + if config.Target != nil && config.Target.InheritableOnly { + return errInheritableOnly + } + // Create a temporary directory for intermediary files. tmpdir, err := os.MkdirTemp("", "tinygo") if err != nil { @@ -357,6 +363,10 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error { return err } + if config.Target != nil && config.Target.InheritableOnly { + return errInheritableOnly + } + // determine the type of file to compile var fileExt string @@ -786,6 +796,10 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error { return err } + if config.Target != nil && config.Target.InheritableOnly { + return errInheritableOnly + } + _, err = buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error { return cmd.Run() }) diff --git a/targets/esp32.json b/targets/esp32.json index 7aad3da4e..2c7abd699 100644 --- a/targets/esp32.json +++ b/targets/esp32.json @@ -1,5 +1,6 @@ { "inherits": ["xtensa"], + "inheritable-only": true, "cpu": "esp32", "features": "+atomctl,+bool,+clamps,+coprocessor,+debug,+density,+dfpaccel,+div32,+exception,+fp,+highpriinterrupts,+interrupt,+loop,+mac16,+memctl,+minmax,+miscsr,+mul32,+mul32high,+nsa,+prid,+regprotect,+rvector,+s32c1i,+sext,+threadptr,+timerint,+windowed", "build-tags": ["esp32", "esp"], diff --git a/targets/esp32c3.json b/targets/esp32c3.json index ea46d0788..583506c19 100644 --- a/targets/esp32c3.json +++ b/targets/esp32c3.json @@ -1,5 +1,6 @@ { "inherits": ["riscv32"], + "inheritable-only": true, "features": "+32bit,+c,+m,+zmmul,-a,-b,-d,-e,-experimental-sdext,-experimental-sdtrig,-experimental-smctr,-experimental-ssctr,-experimental-svukte,-experimental-xqcia,-experimental-xqciac,-experimental-xqcicli,-experimental-xqcicm,-experimental-xqcics,-experimental-xqcicsr,-experimental-xqciint,-experimental-xqcilo,-experimental-xqcilsm,-experimental-xqcisls,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-experimental-zvbc32e,-experimental-zvkgs,-f,-h,-relax,-sha,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smdbltrp,-smepmp,-smmpm,-smnpm,-smrnmi,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssdbltrp,-ssnpm,-sspm,-ssqosid,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-supm,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-svvptc,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xesppie,-xmipscmove,-xmipslsp,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zacas,-zalrsc,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b", "build-tags": ["esp32c3", "esp"], "serial": "usb", diff --git a/targets/esp32s3.json b/targets/esp32s3.json index 281b477df..9eac6dfbd 100644 --- a/targets/esp32s3.json +++ b/targets/esp32s3.json @@ -1,5 +1,6 @@ { "inherits": ["xtensa"], + "inheritable-only": true, "cpu": "esp32s3", "features": "+atomctl,+bool,+clamps,+coprocessor,+debug,+density,+div32,+esp32s3,+exception,+fp,+highpriinterrupts,+interrupt,+loop,+mac16,+memctl,+minmax,+miscsr,+mul32,+mul32high,+nsa,+prid,+regprotect,+rvector,+s32c1i,+sext,+threadptr,+timerint,+windowed", "build-tags": ["esp32s3", "esp"], diff --git a/targets/esp8266.json b/targets/esp8266.json index b6e4a3500..83d5bcd1b 100644 --- a/targets/esp8266.json +++ b/targets/esp8266.json @@ -1,5 +1,6 @@ { "inherits": ["xtensa"], + "inheritable-only": true, "cpu": "esp8266", "features": "+debug,+density,+exception,+extendedl32r,+highpriinterrupts,+interrupt,+mul32,+nsa,+prid,+regprotect,+rvector,+timerint", "build-tags": ["esp8266", "esp"], diff --git a/targets/rp2040.json b/targets/rp2040.json index 6470d57f5..e2969fea5 100644 --- a/targets/rp2040.json +++ b/targets/rp2040.json @@ -1,5 +1,6 @@ { "inherits": ["cortex-m0plus"], + "inheritable-only": true, "build-tags": ["rp2040", "rp"], "scheduler": "tasks", "flash-1200-bps-reset": "true", diff --git a/targets/rp2350.json b/targets/rp2350.json index e3a6549fd..f4567652d 100644 --- a/targets/rp2350.json +++ b/targets/rp2350.json @@ -1,5 +1,6 @@ { "inherits": ["cortex-m33"], + "inheritable-only": true, "build-tags": ["rp2350", "rp"], "scheduler": "tasks", "flash-1200-bps-reset": "true", diff --git a/targets/rp2350b.json b/targets/rp2350b.json index 5db4d4849..6e628c6b7 100644 --- a/targets/rp2350b.json +++ b/targets/rp2350b.json @@ -1,5 +1,6 @@ { "inherits": ["rp2350"], + "inheritable-only": true, "build-tags": ["rp2350b"], "serial-port": ["2e8a:000f"] } \ No newline at end of file