Skip to content

fix filter sketch source #514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion legacy/builder/create_cmake_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func (s *ExportProjectCMake) Run(ctx *types.Context) error {
commands := []types.Command{
//&ContainerMergeCopySketchFiles{},
&ContainerAddPrototypes{},
//&FilterSketchSource{Source: &ctx.Source, RemoveLineMarkers: true},
&FilterSketchSource{Source: &ctx.Source, RemoveLineMarkers: true},
}

for _, command := range commands {
Expand Down
265 changes: 265 additions & 0 deletions legacy/builder/create_cmake_rule.go~
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
/*
* This file is part of Arduino Builder.
*
* Arduino Builder is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/

package builder

import (
"fmt"
"os"
"path/filepath"
"strings"

properties "github.com/arduino/go-properties-orderedmap"

"github.com/arduino/arduino-cli/legacy/builder/builder_utils"
"github.com/arduino/arduino-cli/legacy/builder/constants"
"github.com/arduino/arduino-cli/legacy/builder/i18n"
"github.com/arduino/arduino-cli/legacy/builder/types"
"github.com/arduino/arduino-cli/legacy/builder/utils"
)

var VALID_EXPORT_EXTENSIONS = map[string]bool{".h": true, ".c": true, ".hpp": true, ".hh": true, ".cpp": true, ".s": true, ".a": true, ".properties": true}
var DOTHEXTENSION = map[string]bool{".h": true, ".hh": true, ".hpp": true}
var DOTAEXTENSION = map[string]bool{".a": true}

type ExportProjectCMake struct {
// Was there an error while compiling the sketch?
SketchError bool
}

func (s *ExportProjectCMake) Run(ctx *types.Context) error {
//verbose := ctx.Verbose
logger := ctx.GetLogger()

if s.SketchError || !canExportCmakeProject(ctx) {
return nil
}

// Create new cmake subFolder - clean if the folder is already there
cmakeFolder := ctx.BuildPath.Join("_cmake")
if _, err := cmakeFolder.Stat(); err == nil {
cmakeFolder.RemoveAll()
}
cmakeFolder.MkdirAll()

// Create lib and build subfolders
libBaseFolder := cmakeFolder.Join("lib")
libBaseFolder.MkdirAll()
buildBaseFolder := cmakeFolder.Join("build")
buildBaseFolder.MkdirAll()

// Create core subfolder path (don't create it yet)
coreFolder := cmakeFolder.Join("core")
cmakeFile := cmakeFolder.Join("CMakeLists.txt")

dynamicLibsFromPkgConfig := map[string]bool{}
extensions := func(ext string) bool { return VALID_EXPORT_EXTENSIONS[ext] }
staticLibsExtensions := func(ext string) bool { return DOTAEXTENSION[ext] }
for _, library := range ctx.ImportedLibraries {
// Copy used libraries in the correct folder
libDir := libBaseFolder.Join(library.Name)
mcu := ctx.BuildProperties.Get(constants.BUILD_PROPERTIES_BUILD_MCU)
utils.CopyDir(library.InstallDir.String(), libDir.String(), extensions)

// Read cmake options if available
isStaticLib := true
if cmakeOptions, err := properties.LoadFromPath(libDir.Join("src", mcu, "arduino_builder.properties")); err == nil {
// If the library can be linked dynamically do not copy the library folder
if pkgs, ok := cmakeOptions.GetOk("cmake.pkg_config"); ok {
isStaticLib = false
for _, pkg := range strings.Split(pkgs, " ") {
dynamicLibsFromPkgConfig[pkg] = true
}
}
}

// Remove examples folder
if _, err := libBaseFolder.Join("examples").Stat(); err == nil {
libDir.Join("examples").RemoveAll()
}

// Remove stray folders contining incompatible or not needed libraries archives
var files []string
utils.FindFilesInFolder(&files, libDir.Join("src").String(), staticLibsExtensions, true)
for _, file := range files {
staticLibDir := filepath.Dir(file)
if !isStaticLib || !strings.Contains(staticLibDir, mcu) {
os.RemoveAll(staticLibDir)
}
}
}

// Copy core + variant in use + preprocessed sketch in the correct folders
err := utils.CopyDir(ctx.BuildProperties.Get(constants.BUILD_PROPERTIES_BUILD_CORE_PATH), coreFolder.String(), extensions)
if err != nil {
fmt.Println(err)
}
err = utils.CopyDir(ctx.BuildProperties.Get(constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH), coreFolder.Join("variant").String(), extensions)
if err != nil {
fmt.Println(err)
}

// Use old ctags method to generate export file
commands := []types.Command{
&ContainerMergeCopySketchFiles{},
&ContainerAddPrototypes{},
&FilterSketchSource{Source: &ctx.Source, RemoveLineMarkers: true},
}

for _, command := range commands {
command.Run(ctx)
}

err = utils.CopyDir(ctx.SketchBuildPath.String(), cmakeFolder.Join("sketch").String(), extensions)
if err != nil {
fmt.Println(err)
}

// Extract CFLAGS, CPPFLAGS and LDFLAGS
var defines []string
var linkerflags []string
var dynamicLibsFromGccMinusL []string
var linkDirectories []string

extractCompileFlags(ctx, constants.RECIPE_C_COMBINE_PATTERN, &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories, logger)
extractCompileFlags(ctx, constants.RECIPE_C_PATTERN, &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories, logger)
extractCompileFlags(ctx, constants.RECIPE_CPP_PATTERN, &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories, logger)

// Extract folders with .h in them for adding in include list
var headerFiles []string
isHeader := func(ext string) bool { return DOTHEXTENSION[ext] }
utils.FindFilesInFolder(&headerFiles, cmakeFolder.String(), isHeader, true)
foldersContainingDotH := findUniqueFoldersRelative(headerFiles, cmakeFolder.String())

// Extract folders with .a in them for adding in static libs paths list
var staticLibs []string
utils.FindFilesInFolder(&staticLibs, cmakeFolder.String(), staticLibsExtensions, true)

// Generate the CMakeLists global file

projectName := strings.TrimSuffix(ctx.Sketch.MainFile.Name.Base(), ctx.Sketch.MainFile.Name.Ext())

cmakelist := "cmake_minimum_required(VERSION 3.5.0)\n"
cmakelist += "INCLUDE(FindPkgConfig)\n"
cmakelist += "project (" + projectName + " C CXX)\n"
cmakelist += "add_definitions (" + strings.Join(defines, " ") + " " + strings.Join(linkerflags, " ") + ")\n"
cmakelist += "include_directories (" + foldersContainingDotH + ")\n"

// Make link directories relative
// We can totally discard them since they mostly are outside the core folder
// If they are inside the core they are not getting copied :)
var relLinkDirectories []string
for _, dir := range linkDirectories {
if strings.Contains(dir, cmakeFolder.String()) {
relLinkDirectories = append(relLinkDirectories, strings.TrimPrefix(dir, cmakeFolder.String()))
}
}

// Add SO_PATHS option for libraries not getting found by pkg_config
cmakelist += "set(EXTRA_LIBS_DIRS \"\" CACHE STRING \"Additional paths for dynamic libraries\")\n"

linkGroup := ""
for _, lib := range dynamicLibsFromGccMinusL {
// Dynamic libraries should be discovered by pkg_config
cmakelist += "pkg_search_module (" + strings.ToUpper(lib) + " " + lib + ")\n"
relLinkDirectories = append(relLinkDirectories, "${"+strings.ToUpper(lib)+"_LIBRARY_DIRS}")
linkGroup += " " + lib
}
for lib := range dynamicLibsFromPkgConfig {
cmakelist += "pkg_search_module (" + strings.ToUpper(lib) + " " + lib + ")\n"
relLinkDirectories = append(relLinkDirectories, "${"+strings.ToUpper(lib)+"_LIBRARY_DIRS}")
linkGroup += " ${" + strings.ToUpper(lib) + "_LIBRARIES}"
}
cmakelist += "link_directories (" + strings.Join(relLinkDirectories, " ") + " ${EXTRA_LIBS_DIRS})\n"
for _, staticLib := range staticLibs {
// Static libraries are fully configured
lib := filepath.Base(staticLib)
lib = strings.TrimPrefix(lib, "lib")
lib = strings.TrimSuffix(lib, ".a")
if !utils.SliceContains(dynamicLibsFromGccMinusL, lib) {
linkGroup += " " + lib
cmakelist += "add_library (" + lib + " STATIC IMPORTED)\n"
location := strings.TrimPrefix(staticLib, cmakeFolder.String())
cmakelist += "set_property(TARGET " + lib + " PROPERTY IMPORTED_LOCATION " + "${PROJECT_SOURCE_DIR}" + location + " )\n"
}
}

// Include source files
// TODO: remove .cpp and .h from libraries example folders
cmakelist += "file (GLOB_RECURSE SOURCES core/*.c* lib/*.c* sketch/*.c*)\n"

// Compile and link project
cmakelist += "add_executable (" + projectName + " ${SOURCES} ${SOURCES_LIBS})\n"
cmakelist += "target_link_libraries( " + projectName + " -Wl,--as-needed -Wl,--start-group " + linkGroup + " -Wl,--end-group)\n"

cmakeFile.WriteFile([]byte(cmakelist))

return nil
}

func canExportCmakeProject(ctx *types.Context) bool {
return ctx.BuildProperties.Get("compiler.export_cmake") != ""
}

func extractCompileFlags(ctx *types.Context, receipe string, defines, dynamicLibs, linkerflags, linkDirectories *[]string, logger i18n.Logger) {
command, _ := builder_utils.PrepareCommandForRecipe(ctx, ctx.BuildProperties, receipe, true)

for _, arg := range command.Args {
if strings.HasPrefix(arg, "-D") {
*defines = utils.AppendIfNotPresent(*defines, arg)
continue
}
if strings.HasPrefix(arg, "-l") {
*dynamicLibs = utils.AppendIfNotPresent(*dynamicLibs, arg[2:])
continue
}
if strings.HasPrefix(arg, "-L") {
*linkDirectories = utils.AppendIfNotPresent(*linkDirectories, arg[2:])
continue
}
if strings.HasPrefix(arg, "-") && !strings.HasPrefix(arg, "-I") && !strings.HasPrefix(arg, "-o") {
// HACK : from linkerflags remove MMD (no cache is produced)
if !strings.HasPrefix(arg, "-MMD") {
*linkerflags = utils.AppendIfNotPresent(*linkerflags, arg)
}
}
}
}

func findUniqueFoldersRelative(slice []string, base string) string {
var out []string
for _, element := range slice {
path := filepath.Dir(element)
path = strings.TrimPrefix(path, base+"/")
if !utils.SliceContains(out, path) {
out = append(out, path)
}
}
return strings.Join(out, " ")
}