Протестируйте встроенный код, заменив статические символы во время компиляции - PullRequest
1 голос
/ 23 октября 2019

Справочная информация

Я создаю приложение C для встроенной цели Cortex M4 TI-RTOS SYS / BIOS, однако этот вопрос должен применяться ко всем встроенным целям, в которых используется один двоичный файл. загружен на какой-то микропроцессор.

Что я хочу

Я бы хотел провести некоторые регрессионные тесты на месте на цели, где я просто заменил одну функцию вместо некоторой тестовой функции. Например, функция GetAdcMeasurement () будет возвращать предопределенные значения из массива только для чтения вместо выполнения фактического измерения и возврата этого значения.

Конечно, это может быть сделано путаницей #ifndefs, но я бы предпочел сохранить рабочий код как можно более нетронутым.

Моя попытка

Я полагаю, что одним из способов достижения этого было бы создание дублированных определений символов на этапе компоновщика, а затем компоновщик назначил бы приоритет определениям из тестаsuite (с некоторым #define).

Я изучал использование LD_PRELOAD, но, похоже, это не применимо здесь (поскольку я использую только статические объекты).

Подробнее

Я использую TI Code Composer с TI-RTOS и SYS / BIOS на платформе Sitara AM57xx, компилируя для удаленного процессора M4 (обозначается как IPU1). Вот путь к компилятору и компоновщику

/opt/ti/ccsv7/tools/compiler/ti-cgt-arm_16.9.6.LTS/bin/armcl

Ответы [ 3 ]

2 голосов
/ 23 октября 2019

Один из дополнительных подходов (кроме Пола Огилви) состоит в том, чтобы ваш заголовок-макет также создал определение, которое заменит исходный символ функции на этапе предварительной обработки.

Т.е. если ваш заголовок-макет выглядитthis:

// mock.h

#ifdef MOCKING_ENABLED

  adcdata_t GetAdcMeasurement_mocked(void);
  stuff_t   GetSomeStuff_mocked(void);

  #define GetAdcMeasurement GetAdcMeasurement_mocked
  #define GetSomeStuff GetSomeStuff_mocked

#endif

Тогда всякий раз, когда вы включаете файл, препроцессор заменяет вызовы, прежде чем он даже попадет в компилятор:

#include "mock.h"

void SomeOtherFunc(void)
{
    // preprocessor will change this symbol into 'GetAdcMeasurement_mocked'
    adcdata_t data = GetAdcMeasurement();
}

Такой подход может сбить с толку не подозреваемого читателя вашего кодапотому что они не обязательно поймут, что вы вызываете другую функцию в целом. Тем не менее, я считаю, что этот подход оказывает наименьшее влияние на производственный код (очевидно, кроме добавления include).

2 голосов
/ 23 октября 2019

Одним из решений может быть наличие нескольких файлов .c для каждого модуля, одного производственного кода и одного тестового кода, а также компиляция и связь с одним из двух. Глобальные и функциональные сигнатуры в обоих файлах .c должны быть как минимум одинаковыми (как минимум: символов может быть больше, но не меньше).

Другое решение, основанное на предыдущем, состоит в том, чтобы иметь две библиотекиодин с рабочим кодом, другой с тестовым кодом, и связь с одним из обоих. Вы можете даже связать обе библиотеки с первой тестовой версией, поскольку компоновщики часто разрешают символы в том порядке, в котором они встречаются.

И, как вы сказали, вы можете работать с кучей #ifdef с,что имело бы преимущество иметь только один файл .c, но делая код менее читабельным.

Я бы не стал использовать #ifdef s на уровне функций, то есть определяя только одну функцию файла .cдля проверки и сохранения других как есть;однако, если необходимо, это может быть далеко. И если необходимо, вы можете иметь один файл .c (два) для каждой функции, но это отрицает концепцию модуля.

Я думаю, что первый подход будет самым чистым.

1 голос
/ 23 октября 2019

(это краткое суммирование в комментариях, спасибо за ответы)

Функция может быть переопределена, если она имеет слабый атрибут, см. https://en.wikipedia.org/wiki/Weak_symbol

На GCC это будет слабый атрибут, например,

int __attribute__((weak)) power2(int x);

, а на armcl (как в моем вопросе) это будет директива прагмы

#pragma weak power2

int power2(int x);

Рабочий код, состоящий из частично слабых функций, позволит тестовой среде заменить отдельные функции.

...