Skip to content

Commit

Permalink
Applied a more Modern CMake approach.
Browse files Browse the repository at this point in the history
Split off the Atmel Start specific instructions from toolchain.cmake
into a separate CMakeLists.txt and defined the Atmel Start code as a
separate static library with all the include paths and compile/link
options set as PUBLIC options.
  • Loading branch information
itavero committed May 16, 2021
1 parent 4579e2f commit faee242
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 109 deletions.
2 changes: 1 addition & 1 deletion atmelstart/cmd/atstart/cmd/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var pullCmd = &cobra.Command{
if err := atmelstart.Generate(); err != nil {
logrus.Fatal(err)
}
if err := atmelstart.GenerateCMakeToolchain(); err != nil {
if err := atmelstart.GenerateCMakeFiles(); err != nil {
logrus.Fatal(err)
}
},
Expand Down
21 changes: 19 additions & 2 deletions atmelstart/makefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ import (
"github.com/pkg/errors"
)

var templateCMakeLists *template.Template
var templateToolchain *template.Template

func init() {
templateCMakeLists = templateMustParse("CMakeLists.txt")
templateToolchain = templateMustParse("toolchain.cmake")
}

func GenerateCMakeToolchain() error {
func GenerateCMakeFiles() error {
pathMakefile := path.Join(hiddenDirName, `gcc/Makefile`)
pathCMakeLists := path.Join(hiddenDirName, `CMakeLists.txt`)
pathToolchain := path.Join(hiddenDirName, `toolchain.cmake`)

makefile, err := os.Open(pathMakefile)
Expand All @@ -37,6 +40,15 @@ func GenerateCMakeToolchain() error {
return errors.Wrap(err, "read makefile")
}

cMakeListsFile, err := os.Create(pathCMakeLists)
if err != nil {
return errors.Wrap(err, "open CMakeLists")
}
defer cMakeListsFile.Close()
if err := data.WriteCMakeLists(cMakeListsFile); err != nil {
return errors.Wrap(err, "write CMakeLists")
}

toolchainFile, err := os.Create(pathToolchain)
if err != nil {
return errors.Wrap(err, "open toolchain")
Expand All @@ -56,7 +68,7 @@ func templateMustParse(name string) *template.Template {
return tmpl
}

// Contains all the data we need from 'gcc/Makefile' to create 'toolchain.cmake'.
// Contains all the data we need from 'gcc/Makefile' to create 'CMakeLists.txt'.
type Data struct {

// Source files to compile.
Expand Down Expand Up @@ -98,6 +110,11 @@ func (data *Data) ReadMakefile(r io.Reader) error {
return nil
}

// WriteCMakeLists writes the 'CMakeLists.txt' to the provided writer.
func (data *Data) WriteCMakeLists(w io.Writer) error {
return templateCMakeLists.Execute(w, data)
}

// WriteToolchain writes the 'toolchain.cmake' to the provided writer.
func (data *Data) WriteToolchain(w io.Writer) error {
return templateToolchain.Execute(w, data)
Expand Down
68 changes: 48 additions & 20 deletions atmelstart/templates.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions atmelstart/templates/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
cmake_minimum_required(VERSION 3.13)
include_guard()

# Atmel Start root directory.
set(ATMEL_START_DIR ${CMAKE_CURRENT_LIST_DIR} CACHE PATH "Path to .atstart" FORCE)

# Atmel Start code as static library
add_library(atstart STATIC
# Source files extracted from 'gcc/Makefile'.
{{- range .SourceFiles}}
"${ATMEL_START_DIR}/{{.}}"
{{- end}}
)

# Include directories extracted from 'gcc/Makefile'.
target_include_directories(atstart PUBLIC
{{- range .IncludeDirs}}
"${ATMEL_START_DIR}/{{.}}"
{{- end}}
)

# Bare minimum compiler options
target_compile_options(atstart PUBLIC
-mthumb
-mcpu={{.CPU}}
-D__{{.Device}}__
)

# Apply the default flags that used to be in the toolchain.cmake file previously
# by calling this macro
macro(atstart_use_default_flags)
target_compile_options(atstart PUBLIC
-ffunction-sections
-fdata-sections
-mlong-calls
$<$<COMPILE_LANGUAGE:CXX>:-fno-threadsafe-statics>
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
)
target_link_options(atstart PUBLIC
-Wl,--start-group -lm
-Wl,--end-group
--specs=nano.specs
-Wl,--gc-sections
"-T${ATMEL_START_DIR}/{{.LinkerScript}}"
)
endmacro()

# Have CMake generate an object file out of your elf file
# by calling this macro and passing the name of your target
macro(atstart_create_bin target)
add_custom_command(
TARGET ${target} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${target}> $<TARGET_FILE_BASE_NAME:${target}>.bin
WORKING_DIRECTORY $<TARGET_FILE_DIR:${target}>
)
endmacro()

# Macro kept for backwards compatibility
macro(atstart_add_executable target_name)
atstart_use_default_flags()
add_executable(${target_name} ${ARGN})
target_link_libraries(${target_name} atstart)
atstart_create_bin(${target_name})
endmacro(atstart_add_executable)
146 changes: 78 additions & 68 deletions atmelstart/templates/toolchain.cmake
Original file line number Diff line number Diff line change
@@ -1,75 +1,85 @@
cmake_minimum_required(VERSION 3.0)

# 'Generic' for embedded system without an OS.
cmake_minimum_required(VERSION 3.6)

# Toolchain file to configure the GCC ARM compiler
# ------------------------------------------------------------------------------------
# Inspired by the NXP MCUXpresso toolchain file,
# as well as the one from https://github.com/vpetrigo/arm-cmake-toolchains

# In order to use a specific version of GCC ARM rather than the one on the PATH, you
# can pass the installation path to CMake using -DTOOLCHAIN_DIR=my/custom/path

set(TOOLCHAIN_TRIPLET arm-none-eabi)
if(WIN32)
set(TOOLCHAIN_EXT .exe)
else()
set(TOOLCHAIN_EXT)
endif()

# Determine TOOLCHAIN_DIR (path to GCC ARM installation)
if (NOT DEFINED TOOLCHAIN_DIR)
# If TOOLCHAIN_DIR is already set in the cache or via the command line, do not try to determine it's location
find_program(GCC_ARM_COMPILER_BIN ${TOOLCHAIN_TRIPLET}-gcc REQUIRED)
if (NOT GCC_ARM_COMPILER_BIN)
message(FATAL_ERROR "Unable to find ${TOOLCHAIN_TRIPLET}gcc. Please configure the TOOLCHAIN_DIR variable manually.")
endif()

# Find location where arm-none-eabi-gcc is installed
get_filename_component(TOOLCHAIN_DIR_TEMP ${GCC_ARM_COMPILER_BIN} REALPATH)
get_filename_component(TOOLCHAIN_DIR_TEMP ${TOOLCHAIN_DIR_TEMP} DIRECTORY)
get_filename_component(TOOLCHAIN_DIR_TEMP ${TOOLCHAIN_DIR_TEMP}/.. ABSOLUTE)
if (EXISTS ${TOOLCHAIN_DIR_TEMP})
set(TOOLCHAIN_DIR ${TOOLCHAIN_DIR_TEMP} CACHE PATH "GCC ARM compiler installation path")
message(STATUS "Using GCC ARM from: ${TOOLCHAIN_DIR}")
else()
message(FATAL_ERROR "Failed to determine GCC ARM location: ${TOOLCHAIN_DIR}")
endif()
unset(ARM_GCC CACHE)
unset(TOOLCHAIN_DIR_TEMP CACHE)
endif()
if (NOT DEFINED TOOLCHAIN_DIR OR NOT EXISTS ${TOOLCHAIN_DIR})
message(FATAL_ERROR "GCC ARM location not configured correctly: ${TOOLCHAIN_DIR}")
endif()

# Configure CMake variables
set(CMAKE_SYSTEM_NAME Generic)

# Set C compiler.
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
# Set C++ compiler.
set(CMAKE_C++_COMPILER arm-none-eabi-g++)
# Set objcopy utility.
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)

# Prevents linking issue while testing compiler.
set(CMAKE_SYSTEM_PROCESSOR ARM)
set(CMAKE_EXECUTABLE_SUFFIX_C .elf)
set(CMAKE_EXECUTABLE_SUFFIX_CXX .elf)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

# Set CMAKE_SYSROOT as find_program() root.
set(CMAKE_SYSROOT ${TOOLCHAIN_DIR}/${TARGET_TRIPLET})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Set CMAKE_FIND_ROOT_PATH as find_library() root.
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
# Set CMAKE_FIND_ROOT_PATH as find_file()/find_path() root.
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# Set CMAKE_FIND_ROOT_PATH as find_package() root.
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# Atmel Start root directory.
set(ATMEL_START_DIR ${CMAKE_CURRENT_LIST_DIR})

# Linker script.
set(LINKER_SCRIPT "${ATMEL_START_DIR}/{{.LinkerScript}}")
# Common compiler and linker flags.
set(COMMON_FLAGS "-mthumb -mcpu={{.CPU}}")
# Set compiler flags.
set(CMAKE_C_FLAGS "${COMMON_FLAGS} -Os -ffunction-sections -mlong-calls -g3 -Wall -std=gnu99 -D__{{.Device}}__")
set(CMAKE_CXX_FLAGS "${COMMON_FLAGS} -Os -ffunction-sections -fdata-sections -mlong-calls -g3 -Wall -std=gnu++14 -fno-threadsafe-statics -fno-rtti -fno-exceptions -D__{{.Device}}__")
# Set linker flags.
set(CMAKE_EXE_LINKER_FLAGS "${COMMON_FLAGS} -Wl,--start-group -lm -Wl,--end-group --specs=nano.specs -Wl,--gc-sections -T${LINKER_SCRIPT}")

# Source files extracted from 'gcc/Makefile'.
list(APPEND ATMEL_START_SOURCE_FILES
{{- range .SourceFiles}}
"${ATMEL_START_DIR}/{{.}}"
{{- end}}
)

# Include directories extracted from 'gcc/Makefile'.
list(APPEND ATMEL_START_INCLUDE_DIRS
{{- range .IncludeDirs}}
"${ATMEL_START_DIR}/{{.}}"
{{- end}}
)

macro(atstart_add_executable target_name)

set(elf_name ${target_name}.elf)
set(bin_name ${target_name}.bin)

set(elf_path ${CMAKE_BINARY_DIR}/${elf_name})
set(bin_path ${CMAKE_BINARY_DIR}/${bin_name})

# Outputs elf file.
add_executable(${target_name} ${ARGN} ${ATMEL_START_SOURCE_FILES})

# Rename the elf file.
set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${elf_name})

# Directories to include to compile the elf.
target_include_directories(${target_name} PUBLIC ${ATMEL_START_INCLUDE_DIRS})

# Generate bin file.
add_custom_command(
TARGET ${target_name} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary ${elf_path} ${bin_path}
)

endmacro(atstart_add_executable)
# Configure compilers
set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_DIR}/bin CACHE PATH "GCC ARM compiler bin path")
set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN_TRIPLET}-gcc${TOOLCHAIN_EXT})
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
if (EXISTS ${CMAKE_C_COMPILER})
set(CMAKE_C_FLAGS_DEBUG_INIT "-g3 -Og -gdwarf -Wall -pedantic -DDEBUG")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE)
set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -Wall")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE_INIT}" CACHE STRING "" FORCE)
set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -Wall")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL_INIT}" CACHE STRING "" FORCE)
set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -Wall")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING "" FORCE)
set(CMAKE_ASM_FLAGS_DEBUG_INIT "-g" CACHE INTERNAL "ASM compiler flags Debug")
else()
message(WARNING "C / ASM compiler not found: ${CMAKE_C_COMPILER}")
endif()

set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN_TRIPLET}-g++${TOOLCHAIN_EXT})
if (EXISTS ${CMAKE_CXX_COMPILER})
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g3 -Og -gdwarf -Wall -pedantic -DDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE_INIT}" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -Wall")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL_INIT}" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -Wall")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING "" FORCE)
else()
message(WARNING "C++ compiler not found: ${CMAKE_C_COMPILER}")
endif()
Loading

0 comments on commit faee242

Please sign in to comment.