@@ -35,14 +35,16 @@ import (
3535 "path/filepath"
3636 "strings"
3737
38+ properties "github.com/arduino/go-properties-orderedmap"
39+
3840 "github.com/arduino/arduino-builder/builder_utils"
3941 "github.com/arduino/arduino-builder/constants"
4042 "github.com/arduino/arduino-builder/i18n"
4143 "github.com/arduino/arduino-builder/types"
4244 "github.com/arduino/arduino-builder/utils"
4345)
4446
45- var VALID_EXPORT_EXTENSIONS = map [string ]bool {".h" : true , ".c" : true , ".hpp" : true , ".hh" : true , ".cpp" : true , ".s" : true , ".a" : true }
47+ var VALID_EXPORT_EXTENSIONS = map [string ]bool {".h" : true , ".c" : true , ".hpp" : true , ".hh" : true , ".cpp" : true , ".s" : true , ".a" : true , ".properties" : true }
4648var DOTHEXTENSION = map [string ]bool {".h" : true , ".hh" : true , ".hpp" : true }
4749var DOTAEXTENSION = map [string ]bool {".a" : true }
4850
@@ -76,23 +78,39 @@ func (s *ExportProjectCMake) Run(ctx *types.Context) error {
7678 coreFolder := cmakeFolder .Join ("core" )
7779 cmakeFile := cmakeFolder .Join ("CMakeLists.txt" )
7880
79- // Copy used libraries in the correct folder
81+ dynamicLibsFromPkgConfig := map [ string ] bool {}
8082 extensions := func (ext string ) bool { return VALID_EXPORT_EXTENSIONS [ext ] }
83+ staticLibsExtensions := func (ext string ) bool { return DOTAEXTENSION [ext ] }
8184 for _ , library := range ctx .ImportedLibraries {
85+ // Copy used libraries in the correct folder
8286 libDir := libBaseFolder .Join (library .Name )
87+ mcu := ctx .BuildProperties .Get (constants .BUILD_PROPERTIES_BUILD_MCU )
8388 utils .CopyDir (library .InstallDir .String (), libDir .String (), extensions )
89+
90+ // Read cmake options if available
91+ isStaticLib := true
92+ if cmakeOptions , err := properties .LoadFromPath (libDir .Join ("src" , mcu , "arduino_builder.properties" )); err == nil {
93+ // If the library can be linked dynamically do not copy the library folder
94+ if pkgs , ok := cmakeOptions .GetOk ("cmake.pkg_config" ); ok {
95+ isStaticLib = false
96+ for _ , pkg := range strings .Split (pkgs , " " ) {
97+ dynamicLibsFromPkgConfig [pkg ] = true
98+ }
99+ }
100+ }
101+
84102 // Remove examples folder
85103 if _ , err := libBaseFolder .Join ("examples" ).Stat (); err == nil {
86104 libDir .Join ("examples" ).RemoveAll ()
87105 }
88- // Remove stray folders contining incompatible libraries
89- staticLibsExtensions := func (ext string ) bool { return DOTAEXTENSION [ext ] }
90- mcu := ctx .BuildProperties .Get (constants .BUILD_PROPERTIES_BUILD_MCU )
106+
107+ // Remove stray folders contining incompatible or not needed libraries archives
91108 var files []string
92109 utils .FindFilesInFolder (& files , libDir .Join ("src" ).String (), staticLibsExtensions , true )
93110 for _ , file := range files {
94- if ! strings .Contains (filepath .Dir (file ), mcu ) {
95- os .RemoveAll (filepath .Dir (file ))
111+ staticLibDir := filepath .Dir (file )
112+ if ! isStaticLib || ! strings .Contains (staticLibDir , mcu ) {
113+ os .RemoveAll (staticLibDir )
96114 }
97115 }
98116 }
@@ -127,12 +145,12 @@ func (s *ExportProjectCMake) Run(ctx *types.Context) error {
127145 // Extract CFLAGS, CPPFLAGS and LDFLAGS
128146 var defines []string
129147 var linkerflags []string
130- var libs []string
148+ var dynamicLibsFromGccMinusL []string
131149 var linkDirectories []string
132150
133- extractCompileFlags (ctx , constants .RECIPE_C_COMBINE_PATTERN , & defines , & libs , & linkerflags , & linkDirectories , logger )
134- extractCompileFlags (ctx , constants .RECIPE_C_PATTERN , & defines , & libs , & linkerflags , & linkDirectories , logger )
135- extractCompileFlags (ctx , constants .RECIPE_CPP_PATTERN , & defines , & libs , & linkerflags , & linkDirectories , logger )
151+ extractCompileFlags (ctx , constants .RECIPE_C_COMBINE_PATTERN , & defines , & dynamicLibsFromGccMinusL , & linkerflags , & linkDirectories , logger )
152+ extractCompileFlags (ctx , constants .RECIPE_C_PATTERN , & defines , & dynamicLibsFromGccMinusL , & linkerflags , & linkDirectories , logger )
153+ extractCompileFlags (ctx , constants .RECIPE_CPP_PATTERN , & defines , & dynamicLibsFromGccMinusL , & linkerflags , & linkDirectories , logger )
136154
137155 // Extract folders with .h in them for adding in include list
138156 var headerFiles []string
@@ -141,9 +159,8 @@ func (s *ExportProjectCMake) Run(ctx *types.Context) error {
141159 foldersContainingDotH := findUniqueFoldersRelative (headerFiles , cmakeFolder .String ())
142160
143161 // Extract folders with .a in them for adding in static libs paths list
144- var staticLibsFiles []string
145- isStaticLib := func (ext string ) bool { return DOTAEXTENSION [ext ] }
146- utils .FindFilesInFolder (& staticLibsFiles , cmakeFolder .String (), isStaticLib , true )
162+ var staticLibs []string
163+ utils .FindFilesInFolder (& staticLibs , cmakeFolder .String (), staticLibsExtensions , true )
147164
148165 // Generate the CMakeLists global file
149166
@@ -168,33 +185,39 @@ func (s *ExportProjectCMake) Run(ctx *types.Context) error {
168185 // Add SO_PATHS option for libraries not getting found by pkg_config
169186 cmakelist += "set(EXTRA_LIBS_DIRS \" \" CACHE STRING \" Additional paths for dynamic libraries\" )\n "
170187
171- for i , lib := range libs {
188+ linkGroup := ""
189+ for _ , lib := range dynamicLibsFromGccMinusL {
172190 // Dynamic libraries should be discovered by pkg_config
173- lib = strings .TrimPrefix (lib , "-l" )
174- libs [i ] = lib
175191 cmakelist += "pkg_search_module (" + strings .ToUpper (lib ) + " " + lib + ")\n "
176192 relLinkDirectories = append (relLinkDirectories , "${" + strings .ToUpper (lib )+ "_LIBRARY_DIRS}" )
193+ linkGroup += " " + lib
194+ }
195+ for lib := range dynamicLibsFromPkgConfig {
196+ cmakelist += "pkg_search_module (" + strings .ToUpper (lib ) + " " + lib + ")\n "
197+ relLinkDirectories = append (relLinkDirectories , "${" + strings .ToUpper (lib )+ "_LIBRARY_DIRS}" )
198+ linkGroup += " ${" + strings .ToUpper (lib ) + "_LIBRARIES}"
177199 }
178200 cmakelist += "link_directories (" + strings .Join (relLinkDirectories , " " ) + " ${EXTRA_LIBS_DIRS})\n "
179- for _ , staticLibsFile := range staticLibsFiles {
201+ for _ , staticLib := range staticLibs {
180202 // Static libraries are fully configured
181- lib := filepath .Base (staticLibsFile )
203+ lib := filepath .Base (staticLib )
182204 lib = strings .TrimPrefix (lib , "lib" )
183205 lib = strings .TrimSuffix (lib , ".a" )
184- if ! utils .SliceContains (libs , lib ) {
185- libs = append ( libs , lib )
206+ if ! utils .SliceContains (dynamicLibsFromGccMinusL , lib ) {
207+ linkGroup += " " + lib
186208 cmakelist += "add_library (" + lib + " STATIC IMPORTED)\n "
187- location := strings .TrimPrefix (staticLibsFile , cmakeFolder .String ())
209+ location := strings .TrimPrefix (staticLib , cmakeFolder .String ())
188210 cmakelist += "set_property(TARGET " + lib + " PROPERTY IMPORTED_LOCATION " + "${PROJECT_SOURCE_DIR}" + location + " )\n "
189211 }
190212 }
213+
191214 // Include source files
192215 // TODO: remove .cpp and .h from libraries example folders
193216 cmakelist += "file (GLOB_RECURSE SOURCES core/*.c* lib/*.c* sketch/*.c*)\n "
194217
195218 // Compile and link project
196219 cmakelist += "add_executable (" + projectName + " ${SOURCES} ${SOURCES_LIBS})\n "
197- cmakelist += "target_link_libraries( " + projectName + " -Wl,--as-needed -Wl,--start-group " + strings . Join ( libs , " " ) + " -Wl,--end-group)\n "
220+ cmakelist += "target_link_libraries( " + projectName + " -Wl,--as-needed -Wl,--start-group " + linkGroup + " -Wl,--end-group)\n "
198221
199222 cmakeFile .WriteFile ([]byte (cmakelist ))
200223
@@ -205,26 +228,26 @@ func canExportCmakeProject(ctx *types.Context) bool {
205228 return ctx .BuildProperties .Get ("compiler.export_cmake" ) != ""
206229}
207230
208- func extractCompileFlags (ctx * types.Context , receipe string , defines , libs , linkerflags , linkDirectories * []string , logger i18n.Logger ) {
231+ func extractCompileFlags (ctx * types.Context , receipe string , defines , dynamicLibs , linkerflags , linkDirectories * []string , logger i18n.Logger ) {
209232 command , _ := builder_utils .PrepareCommandForRecipe (ctx , ctx .BuildProperties , receipe , true )
210233
211234 for _ , arg := range command .Args {
212235 if strings .HasPrefix (arg , "-D" ) {
213- * defines = appendIfUnique (* defines , arg )
236+ * defines = utils . AppendIfNotPresent (* defines , arg )
214237 continue
215238 }
216239 if strings .HasPrefix (arg , "-l" ) {
217- * libs = appendIfUnique ( * libs , arg )
240+ * dynamicLibs = utils . AppendIfNotPresent ( * dynamicLibs , arg [ 2 :] )
218241 continue
219242 }
220243 if strings .HasPrefix (arg , "-L" ) {
221- * linkDirectories = appendIfUnique (* linkDirectories , strings . TrimPrefix ( arg , "-L" ) )
244+ * linkDirectories = utils . AppendIfNotPresent (* linkDirectories , arg [ 2 :] )
222245 continue
223246 }
224247 if strings .HasPrefix (arg , "-" ) && ! strings .HasPrefix (arg , "-I" ) && ! strings .HasPrefix (arg , "-o" ) {
225248 // HACK : from linkerflags remove MMD (no cache is produced)
226249 if ! strings .HasPrefix (arg , "-MMD" ) {
227- * linkerflags = appendIfUnique (* linkerflags , arg )
250+ * linkerflags = utils . AppendIfNotPresent (* linkerflags , arg )
228251 }
229252 }
230253 }
@@ -241,10 +264,3 @@ func findUniqueFoldersRelative(slice []string, base string) string {
241264 }
242265 return strings .Join (out , " " )
243266}
244-
245- func appendIfUnique (slice []string , element string ) []string {
246- if ! utils .SliceContains (slice , element ) {
247- slice = append (slice , element )
248- }
249- return slice
250- }
0 commit comments