github.com/atrn/dcc@v0.0.0-20220806184050-4470d2553272/link.go (about) 1 // dcc - dependency-driven C/C++ compiler front end 2 // 3 // Copyright © A.Newman 2015. 4 // 5 // This source code is released under version 2 of the GNU Public License. 6 // See the file LICENSE for details. 7 // 8 9 package main 10 11 import ( 12 "fmt" 13 "os" 14 "path/filepath" 15 "strings" 16 ) 17 18 // Link runs the compiler to link the given inputs and create the given 19 // target using the supplied options. Return a corresponding error 20 // value. If the target exists and is newer than any of the inputs no 21 // linking occurs. 22 func Link(target string, inputs []string, libs *Options, options *Options, otherFiles *Options, frameworks []string) error { 23 if target == "" { 24 target = platform.DefaultExecutable 25 } 26 link := func() error { 27 var args []string 28 args = append(args, options.Values...) 29 args = append(args, inputs...) 30 args = append(args, endash(libs.Values)...) 31 args = append(args, frameworks...) 32 args = append(args, ActualCompiler.DefineExecutableArgs(target)...) 33 if !Quiet { 34 if Verbose { 35 fmt.Fprintln(os.Stdout, ActualCompiler.Name(), strings.Join(args, " ")) 36 } else { 37 fmt.Fprintln(os.Stdout, "ld", target) 38 } 39 } 40 return Exec(ActualCompiler.Name(), args, os.Stderr) 41 } 42 if IgnoreDependencies { 43 return link() 44 } 45 targetInfo, err := Stat(target) 46 if os.IsNotExist(err) { 47 return link() 48 } 49 if err != nil { 50 return err 51 } 52 if MostRecentModTime(options, libs).After(targetInfo.ModTime()) { 53 return link() 54 } 55 newestInput, err := NewestOf(inputs) 56 if err != nil { 57 return err 58 } 59 if newestInput.After(targetInfo.ModTime()) { 60 return link() 61 } 62 if len(otherFiles.Values) > 0 { 63 newest, err := NewestOf(otherFiles.Values) 64 if err != nil { 65 return err 66 } 67 if newest.After(targetInfo.ModTime()) { 68 return link() 69 } 70 } 71 for _, name := range libs.Values { 72 if !strings.HasPrefix(name, "-l") { 73 if libInfo, err := Stat(name); err != nil { 74 return err 75 } else if FileIsNewer(libInfo, targetInfo) { 76 return link() 77 } 78 } 79 } 80 return nil 81 } 82 83 var standardPaths = make(StringSet) 84 85 func endash(values []string) (dashed []string) { 86 if standardPaths.IsEmpty() { 87 for _, name := range platform.LibraryPaths { 88 standardPaths.Insert(name) 89 } 90 } 91 for _, name := range values { 92 dir, base := filepath.Dir(name), filepath.Base(name) 93 if standardPaths.Contains(dir) { 94 s := strings.TrimSuffix(base, platform.StaticLibSuffix) 95 if s == base { 96 s = strings.TrimSuffix(base, platform.DynamicLibSuffix) 97 } 98 t := strings.TrimPrefix(s, platform.StaticLibPrefix) 99 if t == s { 100 t = strings.TrimPrefix(s, platform.DynamicLibPrefix) 101 } 102 dashed = append(dashed, "-l"+t) 103 } else { 104 dashed = append(dashed, name) 105 } 106 } 107 return dashed 108 }