I'm using ATMEL Studio 6.2 and its toolchain with avr-gcc (avr8-gnu-toolchain). I have a variable that needs to be placed in flash (PROGMEM) and I declare it as a global:
static const uint16_t gPrgLen PROGMEM __attribute__((used)) = 0;
The compiler doesn't complain and the linker doesn't complain, but when I open the .lss file, there is no gPrgLen to be found. In the .map file we can see that it has been listed under "discarded input sections"
Discarded input sections
.progmem.data.gPrgLen 0x00000000 0x2 Boot.o
It is built as a release, but a debug build gives the same result.
How can I force the linker to include this variable in the *(.progmem*) section?
EDIT
Added static but still the same result.
Here is the linker part:
# All Target
all: $(OUTPUT_FILE_PATH) $(ADDITIONAL_DEPENDENCIES)
$(OUTPUT_FILE_PATH): $(OBJS) $(USER_OBJS) $(OUTPUT_FILE_DEP) $(LIB_DEP)
#echo Building target: $#
#echo Invoking: AVR/GNU Linker : 4.8.1
$(QUOTE)C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1056\avr8-gnu-toolchain\bin\avr-gcc.exe$(QUOTE) -o$(OUTPUT_FILE_PATH_AS_ARGS) $(OBJS_AS_ARGS) $(USER_OBJS) $(LIBS) -Wl,-Map="Boot.map" -Wl,--start-group -Wl,-lm -Wl,--end-group -Wl,--gc-sections -Wl,-section-start=.text=0xf800 -mmcu=at90usb647
#echo Finished building target: $#
"C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1056\avr8-gnu-toolchain\bin\avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature -R .user_signatures "Boot.elf" "Boot.hex"
"C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1056\avr8-gnu-toolchain\bin\avr-objcopy.exe" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex "Boot.elf" "Boot.eep" || exit 0
"C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1056\avr8-gnu-toolchain\bin\avr-objdump.exe" -h -S "Boot.elf" > "Boot.lss"
"C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1056\avr8-gnu-toolchain\bin\avr-objcopy.exe" -O srec -R .eeprom -R .fuse -R .lock -R .signature -R .user_signatures "Boot.elf" "Boot.srec"
"C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1056\avr8-gnu-toolchain\bin\avr-size.exe" "Boot.elf"
Odd that __attribute__((used)) isn't working. Two suggestions to try.
First, change the variable from static to volatile (or just add volatile). That may prevent it from being optimized away.
If that doesn't work, instead you can add a line to the linker to make it "[p]retend the symbol symbol is undefined, to force linking of library modules to define it" (GCC Link Options). This is done via -u symbol or --undefined=symbol.
To add it to the Atmel Studio project file, go to Toolchain -> AVR/GNU Linker -> Miscellaneous. Then in Other Linker Flags add --undefined=gPrgLen.
I've used this to embed revision/compile-time information into the Hex file where it wasn't otherwise used. That way I could retrieve the memory from a device and know under what conditions it was built (primarily for tracking changes during prototyping and initial firmware debugging). My main.c file had a global char array that looked something like const char codeCompileDetails[] PROGMEM = "company_name-" __DATE__ "-" __TIME__;. Coupled with --undefined=codeCompileDetails, that data (here including the date and time the code was compiled) always makes it into the executable.
Related
I created a file.h and a file.c how can I compile them on Ubuntu?
You only need to compile your .c file(s), not your .h file(s).
To compile file.c on Ubuntu, you can use GCC:
gcc file.c -o my_program
...or Clang:
clang file.c -o my_program
It is possible to precompile your header files, but you only need precompiled headers in particular cases. More information here.
If file.h is not in the same folder as file.c, you can use GCC or Clang's -I option.
Example if file.h is in the include/ folder:
gcc -I include/ file.c -o my_program
In file.c you still have this instruction, with only the filename:
#include "file.h"
You can also use a more generic approach by the usage of a makefile.
Here is a short example of such a file:
# Declaration of variables
CC = gcc
CC_FLAGS = -w -Werror -Wall
# File names
# "prgoram" will be the name of the output produced from the make process
EXEC = program
#Incorporates all the files with .c extension
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.c
$(CC) -c $(CC_FLAGS) $< -o $#
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
To use this utility just make sure that the file itself is within the directory containing your source files and its name is either "makefile" or "Makefile".
To compile the code simply run the following command from your working directory:
make program
This command will automatically link all the source files within your working directory into one executable file with the name of "program". To run the program itself just use the command:
./program
To clean your project and the created executable you can run the command:
make clean
The makefile is very powerful when dealing with larger projects that contain a larger number of source files. Here you can check for more guidance on how to use makefiles. This is also a very detailed tutorial on the topic.
Use following command to compile your program(For GCC Compiler):
gcc file.c -o file
No need to compile file.h file.
I generated a project by the STMCubeMX and wanted to import this project into Clion.
Here's the CmakeList.txt:
project(ClionTest)
cmake_minimum_required(VERSION 3.8)
add_definitions(-DSTM32F4xx)
file(GLOB_RECURSE USER_SOURCES "Src/*.c")
file(GLOB_RECURSE HAL_SOURCES "Drivers/STM32F4xx_HAL_Driver/Src/*.c")
add_library(CMSIS
startup/startup_stm32f407xx.s)
include_directories(Drivers/CMSIS/Device)
include_directories(Drivers/CMSIS/Device/ST/STM32F4xx/Include)
include_directories(Drivers/CMSIS/Include)
include_directories(Drivers/STM32F4xx_HAL_Driver)
include_directories(Drivers/STM32F4xx_HAL_Driver/Inc)
include_directories(Inc)
include_directories(Middlewares/Third_Party/LwIP/src/include)
add_executable(${PROJECT_NAME}.elf ${USER_SOURCES} ${HAL_SOURCES} ${LINKER_SCRIPT})
target_link_libraries(${PROJECT_NAME}.elf CMSIS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${PROJECT_SOURCE_DIR}/build/${PROJECT_NAME}.map")
set(HEX_FILE ${PROJECT_SOURCE_DIR}/build/${PROJECT_NAME}.hex)
set(BIN_FILE ${PROJECT_SOURCE_DIR}/build/${PROJECT_NAME}.bin)
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}
COMMENT "Building ${HEX_FILE} \nBuilding ${BIN_FILE}")
And a STM32F4xx.cmake file:
INCLUDE(CMakeForceCompiler)
SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)
# specify the cross compiler
#CMAKE_FORCE_C_COMPILER(C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q2-update/bin/arm-none-eabi-gcc.exe GNU)
#CMAKE_FORCE_CXX_COMPILER(D:/Lib/arm/bin/arm-none-eabi-g++.exe GNU)
SET(CMAKE_C_COMPILER "C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q2-update/bin/arm-none-eabi-gcc.exe")
SET(CMAKE_CXX_COMPILER "C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q2-update/bin/arm-none-eabi-g++.exe")
SET(LINKER_SCRIPT ${PROJECT_SOURCE_DIR}/STM32F407VETx_FLASH.ld)
#Uncomment for software floating point
#SET(COMMON_FLAGS "-mcpu=cortex-m4 -mthumb -mthumb-interwork -mfloat-abi=soft -ffunction-sections -fdata-sections -g -fno-common -fmessage-length=0")
SET(COMMON_FLAGS "-mcpu=cortex-m4 -mthumb -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections -g -fno-common -fmessage-length=0")
SET(CMAKE_CXX_FLAGS_INIT "${COMMON_FLAGS} -std=c++11")
SET(CMAKE_C_FLAGS_INIT "${COMMON_FLAGS} -std=gnu99")
SET(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,-gc-sections,-M=binary.map -T ${LINKER_SCRIPT}")
I set LINKER_SCRIPT ${PROJECT_SOURCE_DIR}/STM32F407VETx_FLASH.ld
File structure
And the Cmake options is:
Cmake options
When I reload this project, it's not go on well.
c:/progra~2/gnutoo~1/62017-~1/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/bin/ld.exe: cannot open linker script file
D:/Project/ClionTest/cmake-build-default/CMakeFiles/CMakeTmp/STM32F407VETx_FLASH.ld:
Invalid argument
collect2.exe: error: ld returned 1 exit status
CMakeFiles\cmTC_bf7b4.dir\build.make:96: recipe for target 'cmTC_bf7b4' failed
mingw32-make.exe[1]: *** [cmTC_bf7b4] Error 1
mingw32-make.exe[1]: Leaving directory
'D:/Project/ClionTest/cmake-build-default/CMakeFiles/CMakeTmp'
Makefile:125: recipe for target 'cmTC_bf7b4/fast' failed
mingw32-make.exe: *** [cmTC_bf7b4/fast] Error 2
It seems like the path of ld.exe is not correct,how shoulld I set its path?
And why the path of STM32F407VETx_FLASH.ld it searched is not the path I set?
I'm using Linux, but I've had the a similar issue in regards to being unable to open the linker script.
cannot open linker script file D:/Project/ClionTest/cmake-build-default/CMakeFiles/CMakeTmp/STM32F407VETx_FLASH.ld
After looking for a while at the documentation for target_link_option (which does approximately the same kind of thing as setting a variable directly), I took note of the SHELL: directive, that's stated to:
The set of options is de-duplicated to avoid repetition. While beneficial for individual options, the de-duplication step can break up option groups. For example, -D A -D B becomes -D A B. One may specify a group of options using shell-like quoting along with a SHELL: prefix. The SHELL: prefix is dropped and the rest of the option string is parsed using the separate_arguments() UNIX_COMMAND mode.
By adding it to my command, I managed to get compilation working normally. The result was the following:
set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/STM32F303CCTX_FLASH.ld")
set(LINKER_FLAGS "SHELL:-T${LINKER_SCRIPT} -Wl,--gc-sections --specs=nano.specs --specs=nosys.specs")
target_link_options(${PROJECT_BINARY} PRIVATE ${LINKER_FLAGS})
Change this:
SET(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,-gc-sections,-M=binary.map -T ${LINKER_SCRIPT}")
To:
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,-gc-sections,-M=binary.map -T${LINKER_SCRIPT}")
I'm trying to get libtool and yasm to work together.
yasm creates the correct .o files from my .asm sources, but I can't figure out how to get libtool to build the associated .lo and .dep files.
It wants to build the shared library, incorporating the .o files.
libtool generated files typically use the following layout: The .lo file in a build directory consisting of location metadata; the static object .o files in the build directory; and the PIC / shared .o objects in the build/.libs directory.
You can use the libtool compile mode. I'm not familiar with yasm, so you'll have to fill in the switches. It will run the yasm build twice, once with -DPIC (and maybe other shared object options).
libtool --tag=CC --mode=compile yasm <options> src.asm
If using automake, this may require an explicit rule for the .asm files:
.asm.lo:
$(LIBTOOL) --tag=CC --mode=compile \
yasm <options> $<
Keep in mind that those are TABs in Makefiles, not (8) space characters!
You might also need to add: .SUFFIXES: .asm .lo prior to this. I use the variable $(LIBTOOL), because some platforms (OSX for example) need to install it as glibtool, and it's what Makefile.indoes.
The generated src.lo, src.o, .libs/src.o should be respected by make clean for example.
For your library libfoo, you will need to let automake know about these sources with: EXTRA_libfoo_la_SOURCES = src.asm, and obj deps with libfoo_la_LIBADD = src.lo. It might be even be worthwhile adding to dependencies: libfoo_la_DEPENDENCIES = src.lo.
Though I don't see why just putting src.asm in libfoo_la_SOURCES wouldn't be sufficient.
This works (although I never did figure out how to get libtool to create the .lo file in the target directory, or to create the target directory's .libs directory).
The Makefile rule:
# Rule to build object files from asm files.
#
# XXX
# Libtool creates the .lo file in the directory where make is run. Move the file
# into place explicitly; I'm sure this is wrong, but have no idea how to fix it.
# Additionally, in a parallel make, the .libs file may not yet be created, check
# as necessary, but ignore errors.
.asm.lo:
-d=`dirname $#`; test $d/.libs || mkdir $d/.libs
$(LIBTOOL) --tag=CC --mode=compile sh $(srcdir)/dist/yasm.sh $< $#
rm -f $#
mv `basename $#` $#
A support shell script to do the yasm call:
#! /bin/sh
# Libtool support for yasm files, expect the first argument to be a path to
# the source file and the second argument to be a path to libtool's .lo file.
# Use the second argument plus libtool's -o argument to set the real target
# file name.
source=$1
target=`dirname $2`
while test $# -gt 0
do
case $1 in
-o)
target="$target/$2"
shift; shift;;
*)
shift;;
esac
done
yasm -f x64 -f elf64 -X gnu -g dwarf2 -D LINUX -o $target $source
I'm on Windows 7 and have MinGW/gcc installed. I'm using the Eclipse CDT plugin to compile and build my first simple C programs, and am trying to follow what exactly the plugin is doing under the hood.
I create a new "Hello World!" C project with the following directory structure:
helloworld/
src/
helloworld.c
Where helloworld.c is:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
puts("Hello World!");
return EXIT_SUCCESS;
}
So I created a Run Configuration in Debug Mode (as opposed to "Release Mode", not a "Debug Configuration" in typical Eclipse parlance!) and ran my app, and it works beautifully, printing "Hello World!" to the Eclipse console.
Now I'm looking on my file system and the file/project structure is like so:
helloworld/
src/
helloworld.c
Debug/
src/
helloworld.d
helloworld.o
subdir.mk
helloworld.exe
makefile
objects.mk
source.mk
I assume that running my Run Configuration in Eclipse (hence compiling/building/running helloworld inside Eclipse) created everything under Debug. Furthermore I assume that helloworld.d and helloworld.o are compiled binaries, and that helloworld.exe is the packaged executable containing those binaries and everything they'red linked to (stdio and stdlib). I also assume makefile is the actual Make file (buildscript), and that the *.mk files are somehow inputs to that buildscript. So, for starters, if any of those assumptions are wrong, please begin by correcting me!
When I open makefile I see this:
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
-include ../makefile.init
RM := rm -rf
# All of the sources participating in the build are defined here
-include sources.mk
-include src/subdir.mk
-include subdir.mk
-include objects.mk
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
endif
-include ../makefile.defs
# Add inputs and outputs from these tool invocations to the build variables
# All Target
all: helloworld
# Tool invocations
helloworld: $(OBJS) $(USER_OBJS)
#echo 'Building target: $#'
#echo 'Invoking: Cross GCC Linker'
gcc -o "helloworld" $(OBJS) $(USER_OBJS) $(LIBS)
#echo 'Finished building target: $#'
#echo ' '
# Other Targets
clean:
-$(RM) $(EXECUTABLES)$(OBJS)$(C_DEPS) helloworld
-#echo ' '
.PHONY: all clean dependents
.SECONDARY:
-include ../makefile.targets
Please note: I am not looking for someone to explain to me how Make works, I can RTFM for that ;-)
I am just trying to understand what it would take to compile, build and run helloworld from the command-line, outside of Eclipse. What command line invocations would I need to accomplish this, and why? Once I see that, combined with perusing Make docs, I should be able to fill in the gaps and understand everything that is going on.
That depends a bit on the paths that Eclipse generates in the files source.mk and objects.mk but most likely you need to cd into the Debug folder.
Inside of that, you can then run make all to compile the project.
If Eclipse generated absolute paths, you can use make -f .../path/to/helloworld/Debug/makefile all from anywhere.
The *.o files are the object file(s) created by compilation. these files are typically build by a command like:
Gcc -ansi -Wall -pedantic -c helloworld.c -o helloworld.o
(apologies foe capitalization of gcc, my iPad insists on correct my typing)
The *.exe is the actual executable, which may or may not contain the library functions. This depends on static versus dynamic linking. The executable is created typically by:
Gcc helloworld.o -o helloworld.exe
The *.d files are dependency files, built by gcc attempting to determine dependencies between files, typically built with the following command
MAKEDEPEND = gcc -M $(CPPFLAGS) -o $*.d $<
(Rule taken from make online documentation).
So,to answer your final question, to compile from the command line, a command like:
Foo gcc -ansi -WAll -pedantic helloworld.c -o helloworld.exe
Should do the trick for you. Note, the flags to the compiler are the minimum that I like to use, you will probably have a different set of switches.
Hopes this help,
T
I need to compile an old application whose tarball only contains *.c and *h, ie. no Makefile. The root directory contains the application, and a sub-directory contains a library the application needs.
My make/Makefile knowledge isn't great, and I was wondering what the easiest way would be to compile this application + library.
Thank you.
Edit: Using this script...
# cat compile.bash
#!/bin/bash
cd mylib
for cfile in *.c; do
ofile=$(echo "$cfile" | sed 's#.c$#.so#')
gcc -shared -c "$cfile" -o "$ofile"
done
cd ..
gcc *.c -I mylib -L mylib -mylib -o myapp
... I notice that each *.c file in mylib/ is compiled into a *.so file instead of compiling each into an object file and building a single .so file, and I get tons of warnings and errors, eg.
unzip.c: In function âunzipâ:
unzip.c:991: warning: format not a string literal and no format arguments
gcc: unrecognized option '-mylib'
file_util.c: In function âfile_moveâ:
file_util.c:98: error: âerrnoâ undeclared (first use in this function)
I don't know how to compile the library, and then compile the application without error/warning.
No need to use a for loop or generate intermediate object files:
(cd mylib && gcc -shared -fPIC -o libfoo.so *.c) && \
gcc -Imylib -o app *.c mylib/libfoo.so
Compile the library:
cd libfoo
for cfile in *.c; do
ofile=$(echo "$cfile" | sed 's#.c$#.so#')
gcc -shared -c "$cfile" -o "$ofile"
done
After this, you should have a libfoo.so file in libfoo/. Then, compile the program (Don't forget to cd back):
gcc *.c -I libfoo -L libfoo -lfoo -o application
The easiest is probably to get an IDE to do the build for you. Netbeans for one will create a Makefile so you can then build the project independently of the IDE.