Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: AVR mixing c/cpp, makefile, build shell, atmega328 - trouble
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
sunjob
AVR mixing c/cpp, makefile, build shell, atmega328 - trouble

добрый день

linux, avr-gcc, mixing c/cpp codes, makefile, build on shell, atmega-328p, NO ARDUINO, NO IDE/AVR-Studio/Eclipse/etc, NO_WINDOWS

проект простой "шаблон", изучаю "топик", в частности "c/cpp mixing"

- два модуля, один си, другой си++, оба имеют хедеры (func.c/h func.cpp/h), в хедерах описание функции и массива
- главный модуль main, в "процессе" меняется расширение, c/cpp (main.*)
- итого: имеем два модуля си/си++ и главный модуль тоже "меняет" свой окрас :о)
- сборка: makefile & bash
- собираем, смотрим как ведет себя "смешанный код"

итого:
если главный модуль си / main.c - ни каких проблем, проект собирается нормально
если главный модуль си++ / main.cpp - ошибка линковки: множ.определение массива в си++ модуле
makefile & bash выдают одинаковый результат
модификатор 'extern "C"' - в данном случае, естественно, не помогает
ошибка: multiple definition of mass_cpp[]

...

проанализировал выхлоп makefile, все, вроде, идеально
выкусы команд скинул в файл build_cmd.txt
команды идут парами, первая строка "сценарий с ошибкой", вторая "нормальна"
единственное отличие - последовательность сборки, пробывал мануально собирать и менять последовательность, на конечный результат не влияет

...

(тему изучил но ...:о)

итак, высказываемся, предполагаем, просто философствуем

...

linux x32
avr-binutils-2.25
avr-gcc-4.9.2
avr-gdb-7.8.1
avr-libc-1.8.1
option:
avr-gcc-toolchain-3.4.2
avr-gcc-toolchain-3.5.4

...

содержание проекта (не нашел спойлер)
CODE
///////////////////////////////////////////////////////////////////////////////
// main.*
///////////////////////////////////////////////////////////////////////////////
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>

#include "src/func_c.h"
#include "src/func_cpp.h"

int main(void)
{
func_c();
func_cpp();
}
///////////////////////////////////////////////////////////////////////////////
// func_c.h
///////////////////////////////////////////////////////////////////////////////
#ifndef _FUNC_C_H_
#define _FUNC_C_H_

#ifdef __cplusplus
extern "C" {
#endif

int mass_c[8];
void func_c(void);

#ifdef __cplusplus
}
#endif

#endif
///////////////////////////////////////////////////////////////////////////////
// func_c.c
///////////////////////////////////////////////////////////////////////////////
#include "func_c.h"
void func_c(void) {;}

///////////////////////////////////////////////////////////////////////////////
// func_cpp.h
///////////////////////////////////////////////////////////////////////////////
#ifndef _FUNC_CPP_H_
#define _FUNC_CPP_H_

#ifdef __cplusplus
extern "C" {
#endif

int mass_cpp[8];
void func_cpp(void);

#ifdef __cplusplus
}
#endif

#endif
///////////////////////////////////////////////////////////////////////////////
// func_cpp.cpp
///////////////////////////////////////////////////////////////////////////////
#include "func_cpp.h"
void func_cpp(void) {;}

///////////////////////////////////////////////////////////////////////////////
// содержание баш-скрипта
///////////////////////////////////////////////////////////////////////////////
#!/bin/sh
set -e; clear

CLK=16000000
MAIN=main.cpp
FUNC1=func_c.c
FUNC2=func_cpp.cpp
OUT=out
CPU=atmega328p

rm -fr $OUT; mkdir -p $OUT

echo "===> gcc $FUNC1"
avr-gcc -mmcu=$CPU -Wall -Os -DF_CPU=$CLK -c -o $OUT/$FUNC1.elf src/$FUNC1

echo "===> gcc $FUNC2"
avr-gcc -mmcu=$CPU -Wall -Os -DF_CPU=$CLK -c -o $OUT/$FUNC2.elf src/$FUNC2

echo "===> gcc $MAIN"
avr-gcc -mmcu=$CPU -Wall -Os -DF_CPU=$CLK -c -o $OUT/$MAIN.elf $MAIN

echo "===> gcc links"
# var.1
avr-gcc -mmcu=$CPU -Wall -DF_CPU=$CLK -o $OUT/x.elf $OUT/$MAIN.elf $OUT/$FUNC1.elf $OUT/$FUNC2.elf

# var.2 - выкус эха makefile
#avr-gcc -mmcu=$CPU -g -DF_CPU=$CLK -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef \
#-Wa,-adhlns=out/func_c.o -std=gnu99 \
#out/func_c.c.elf out/func_cpp.cpp.elf out/main.cpp.elf --output out/main.elf -Wl,-Map=out/main.map,--cref -lm

echo "===> objcopy"
cd $OUT
#avr-objcopy -O ihex $MAIN.elf $MAIN.hex
# -->
avr-objcopy -O ihex x.elf $MAIN.hex
cd -

echo "### OK $0 ###"; sleep 1


tag: linux, avr-gcc, mixing c/cpp codes, makefile, build on shell, atmega-328p, NO ARDUINO, NO IDE/AVR-Studio/Eclipse/etc, NO_WINDOWS
Сергей Борщ
Перенесите определение вашего массива в main.cpp. В заголовочном файле оставьте объявление вашего массива extern int mass_c[8]; Почитайте о правиле единственного определения (one definition rule).

extern "C" относится к функциям и служит для отключения декорирования имен (name mangling), которое для переменных смысла не имеет.

Совет: не злоупотребляйте жирным шрифтом и метки (tags) на этом форуме тоже не работают.
sunjob
Цитата
Перенесите определение вашего массива в main.cpp

разобрался уже rolleyes.gif
а так, массиву в главном модуле делать нечего... в тело своего модуля его надо вставлять...

Цитата
метки (tags) на этом форуме тоже не работают

это не для форума sm.gif а для людей

Цитата
one definition rule

в данном случае это не проблема а последствие sm.gif

спасибо
Сергей Борщ
QUOTE (sunjob @ Apr 30 2018, 10:44) *
это не для форума sm.gif а для людей
Как человек, не вижу никакой пользы в бессмысленном наборе слов.

QUOTE (sunjob @ Apr 30 2018, 10:44) *
в данном случае это не проблема а последствие sm.gif
Внезапно. Линковщик ругался на нарушение именно этого правила. Впрочем, считайте как хотите.
sunjob
Цитата
не вижу никакой пользы

до тех пор пока не посоветовали "набить код в ардуине", вставить его в avr-studio или еще какой эклипс...
сразу и смысл и польза проявится rolleyes.gif

Цитата
Внезапно. Линковщик ругался на нарушение именно этого правила

как последствие -fno-common

...

### UPDATE ### - сборка в 3х вариантах

с миксами, вроде как разобрался, продолжаю исследования в разрезе вариантов сборки
- makefile
- avr-gcc shell
- avr-gcc shell, single mode


первый вариант - сборка с пом-ю makefile
второй - с пом-ю шелл-скрипта (компиляция по отдельности файлов, потом сборка "все в кучу")
третий - попытаться инклудами в главном модуле собрать "общий код" в одном месте (надеюсь понятно?), так, что-бы достаточно было компилировать только один главный модуль, плюс ко всему прочему добавил флаг сборки BUILD_SINGLE и условиями препроцессора переношу определение массива из тела C/C++ в хедер файл, (и для эмуляции более логичного и понятного для меня понимания что-где должно лежать sm.gif

как итог
- сборка и тест всех трех вариантов - без ошибок, для отладки использую вывод на терминал
- размеры hex-файла:
6486 - makefile
3540 - avr-gcc shell (md5-отличается)

вопросы по ходу:
- почему у makefile - чуть ли не в два раза больше? оптимизация во всех случаях -Os, могу предположить, что makefile что-то дополнилтельно пихает (ну... что сказали, то и пихает)
- подводные камни третьего варианта? (для меня он наиболее понятен и прозрачен, и хотелось бы уточнить тонкости, особенности)

и как обычно - высказываемся, предполагаем, просто философствуем
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.