Merge pull request #15002 from kaspar030/pr/xfa_v3

core: introduce crossfile arrays (xfa) v3
This commit is contained in:
Kaspar Schleiser 2021-02-18 14:49:22 +01:00 committed by GitHub
commit 15124e4769
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 667 additions and 6 deletions

View File

@ -416,6 +416,10 @@ TOOLCHAINS_SUPPORTED ?= gnu
# Import all toolchain settings # Import all toolchain settings
include $(RIOTMAKE)/toolchain/$(TOOLCHAIN).inc.mk include $(RIOTMAKE)/toolchain/$(TOOLCHAIN).inc.mk
# Append ldscript path after importing CPU and board makefiles to allow
# overriding the core ldscripts
LINKFLAGS += -L$(RIOTBASE)/core/ldscripts
# Tell ccache to pass the original file to the compiler, instead of passing the # Tell ccache to pass the original file to the compiler, instead of passing the
# preprocessed code. Without this setting, the compilation will fail with # preprocessed code. Without this setting, the compilation will fail with
# -Wimplicit-fallthrough warnings even when the fall through case is properly # -Wimplicit-fallthrough warnings even when the fall through case is properly

View File

@ -59,6 +59,9 @@ else
LINKFLAGS += -ldl LINKFLAGS += -ldl
endif endif
# XFA (cross file array) support
LINKFLAGS += -T$(RIOTBASE)/cpu/native/ldscripts/xfa.ld
# clean up unused functions # clean up unused functions
CFLAGS += -ffunction-sections -fdata-sections CFLAGS += -ffunction-sections -fdata-sections
ifeq ($(OS),Darwin) ifeq ($(OS),Darwin)

186
core/include/xfa.h Normal file
View File

@ -0,0 +1,186 @@
/*
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup core_util
* @brief Cross File Arrays
* @{
*
* This macro, in combination with an entry in the linker scripts, allows the
* definition of constant arrays to be spread over multiple C compilation
* units. These arrays are called "cross-file arrays" or short xfa.
*
* @experimental This API is considered experimental and will probably change
* without notice!
*
* @file
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef XFA_H
#define XFA_H
/*
* Unfortunately, current gcc trips over accessing XFA's because of their
* zero-size start/end array that are used of symbol markers, with an "array
* index out of bounds" warning. So until a solution for that is found, we
* need to disable array bounds checks for files using XFAs.
*/
#ifndef DOXYGEN
_Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
#endif
/**
* @brief helper macro for other XFA_* macros
*
* @internal
*/
#define _XFA(name, prio) __attribute__((used, section(".xfa." #name "." #prio)))
/**
* @brief helper macro for other XFA_* macros
*
* @internal
*/
#define _XFA_CONST(name, \
prio) __attribute__((used, \
section(".roxfa." #name "." #prio)))
/**
* @brief Define a read-only cross-file array
*
* This macro defines the symbols necessary to use XFA_START() and XFA_END().
* It needs to be part of one single compilation unit.
*
* The pragmas prevent these errors:
*
* error: ISO C forbids empty initializer braces
* error: ISO C forbids zero-size array xfatest_const_end
*
* @param[in] type name of the cross-file array
* @param[in] name name of the cross-file array
*/
#define XFA_INIT_CONST(type, name) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
_XFA_CONST(name, 0_) const volatile type name [0] = {}; \
_XFA_CONST(name, 9_) const volatile type name ## _end [0] = {}; \
_Pragma("GCC diagnostic pop") \
extern const unsigned __xfa_dummy
/**
* @brief Define a writable cross-file array
*
* This macro defines the symbols necessary to use XFA_START() and XFA_END().
* It needs to be part of one single compilation unit.
*
* The pragmas prevent these errors:
*
* error: ISO C forbids empty initializer braces
* error: ISO C forbids zero-size array xfatest_end
*
* @param[in] type name of the cross-file array
* @param[in] name name of the cross-file array
*/
#define XFA_INIT(type, name) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
_XFA(name, 0_) type name [0] = {}; \
_XFA(name, 9_) type name ## _end [0] = {}; \
_Pragma("GCC diagnostic pop") \
extern const unsigned __xfa_dummy
/**
* @brief Declare an external read-only cross-file array
*
* This macro defines the symbols necessary to use XFA_START() and XFA_END().
* Think of this as XFA_INIT() but with "extern" keyword.
* It is supposed to be used in compilation units where the cross file array is
* being accessed, but not defined using XFA_INIT.
*
* @param[in] type name of the cross-file array
* @param[in] name name of the cross-file array
*/
#define XFA_USE_CONST(type, name) \
extern const type name []; \
extern const type name ## _end []
/**
* @brief Declare an external writable cross-file array
*
* This macro defines the symbols necessary to use XFA_START() and XFA_END().
* Think of this as XFA_INIT() but with "extern" keyword.
* It is supposed to be used in compilation units where the cross file array is
* being accessed, but not defined using XFA_INIT.
*
* @param[in] type name of the cross-file array
* @param[in] name name of the cross-file array
*/
#define XFA_USE(type, name) \
extern type name []; \
extern type name ## _end []
/**
* @brief Define variable in writable cross-file array
*
* Variables will end up sorted by prio.
*
* Add this to the type in a variable definition, e.g.:
*
* XFA(driver_params, 0) driver_params_t _onboard = { .pin=42 };
*
* @param[in] xfa_name name of the xfa
* @param[in] prio priority within the xfa
*/
#define XFA(xfa_name, prio) _XFA(xfa_name, 5_ ## prio)
/**
* @brief Define variable in read-only cross-file array
*
* Variables will end up sorted by prio.
*
* Add this to the type in a variable definition, e.g.:
*
* XFA(driver_params, 0) driver_params_t _onboard = { .pin=42 };
*
* @param[in] xfa_name name of the xfa
* @param[in] prio priority within the xfa
*/
#define XFA_CONST(xfa_name, prio) _XFA_CONST(xfa_name, 5_ ## prio)
/**
* @brief Add a pointer to cross-file array
*
* Pointers will end up sorted by prio.
*
* @param[in] xfa_name name of the xfa
* @param[in] prio priority within the xfa
* @param[in] name symbol name
* @param[in] entry pointer variable to add to xfa
*/
#define XFA_ADD_PTR(xfa_name, prio, name, entry) \
_XFA_CONST(xfa_name, 5_ ## prio) \
const typeof(entry) xfa_name ## _ ## prio ## _ ## name = entry
/**
* @brief Calculate number of entries in cross-file array
*/
#define XFA_LEN(type, \
name) (((const char *)name ## _end - (const char *)name) / \
sizeof(type))
#ifdef __cplusplus
extern "C" {
#endif
/* making externc happy */
#ifdef __cplusplus
}
#endif
#endif /* XFA_H */
/** @} */

View File

@ -0,0 +1,16 @@
SECTIONS
{
.data :
{
/* Special case for AVR (Harvard architecture) where .rodata is merged
* into .data by the toolchain default ldscripts. */
KEEP (*(SORT(.roxfa.*)))
KEEP (*(SORT(.xfa.*)))
}
__data_start = ADDR(.data);
__data_load_start = LOADADDR(.data);
__data_end = (__data_start + SIZEOF(.data));
__data_load_end = (__data_load_start + SIZEOF(.data));
}
INSERT AFTER .text;

View File

@ -55,6 +55,7 @@ SECTIONS
*(.text .text.* .gnu.linkonce.t.*) *(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7) *(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*) *(.rodata .rodata* .gnu.linkonce.r.*)
KEEP (*(SORT(.roxfa.*)))
*(.ARM.extab* .gnu.linkonce.armextab.*) *(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code /* Support C constructors, and C destructors in both user code
@ -167,6 +168,7 @@ SECTIONS
_srelocate = .; _srelocate = .;
*(.ramfunc .ramfunc.*); *(.ramfunc .ramfunc.*);
*(.data .data.*); *(.data .data.*);
KEEP (*(SORT(.xfa.*)))
KEEP (*(.openocd .openocd.*)) KEEP (*(.openocd .openocd.*))
. = ALIGN(4); . = ALIGN(4);
_erelocate = .; _erelocate = .;

View File

@ -158,6 +158,7 @@ SECTIONS
_data_start = ABSOLUTE(.); _data_start = ABSOLUTE(.);
*(.data) *(.data)
*(.data.*) *(.data.*)
KEEP (*(SORT(.xfa.*)))
*(.gnu.linkonce.d.*) *(.gnu.linkonce.d.*)
*(.data1) *(.data1)
*(.sdata) *(.sdata)
@ -243,6 +244,7 @@ SECTIONS
_rodata_start = ABSOLUTE(.); _rodata_start = ABSOLUTE(.);
*(.rodata) *(.rodata)
*(.rodata.*) *(.rodata.*)
KEEP (*(SORT(.roxfa.*)))
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
*(.gnu.linkonce.r.*) *(.gnu.linkonce.r.*)
*(.rodata1) *(.rodata1)

View File

@ -61,9 +61,10 @@ endif
ARCHIVES += -lgcc -lwpa -lcore -lnet80211 -lphy -lpp -lstdc++ ARCHIVES += -lgcc -lwpa -lcore -lnet80211 -lphy -lpp -lstdc++
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.rom.ld LINKFLAGS += -L$(RIOTCPU)/$(CPU)/ld
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.ld LINKFLAGS += -Tesp8266.rom.ld
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.peripherals.ld LINKFLAGS += -Tesp8266.riot-os.ld
LINKFLAGS += -Tesp8266.peripherals.ld
LINKFLAGS += -Wl,-wrap=pp_attach LINKFLAGS += -Wl,-wrap=pp_attach
LINKFLAGS += -Wl,-wrap=pm_attach LINKFLAGS += -Wl,-wrap=pm_attach

View File

@ -105,6 +105,7 @@ SECTIONS
*(.sdata2.*) *(.sdata2.*)
*(.gnu.linkonce.s2.*) *(.gnu.linkonce.s2.*)
*(.jcr) *(.jcr)
KEEP (*(SORT(.xfa.*)))
_data_end = ABSOLUTE(.); _data_end = ABSOLUTE(.);
} >dram0_0_seg :dram0_0_phdr } >dram0_0_seg :dram0_0_phdr
@ -139,6 +140,7 @@ SECTIONS
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*))) KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors)) KEEP (*(.dtors))
KEEP (*(SORT(.roxfa.*)))
/* C++ exception handlers table: */ /* C++ exception handlers table: */
__XT_EXCEPTION_DESCS__ = ABSOLUTE(.); __XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
*(.xt_except_desc) *(.xt_except_desc)

View File

@ -65,6 +65,7 @@ SECTIONS
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*))) KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors)) KEEP (*crtend.o(.dtors))
KEEP (*(SORT(.roxfa.*)))
. = ALIGN(4); . = ALIGN(4);
_efixed = .; /* End of text section */ _efixed = .; /* End of text section */
@ -163,6 +164,7 @@ SECTIONS
*(.ramfunc .ramfunc.*); *(.ramfunc .ramfunc.*);
*(.data .data.*); *(.data .data.*);
KEEP (*(.openocd .openocd.*)) KEEP (*(.openocd .openocd.*))
KEEP (*(SORT(.xfa.*)))
. = ALIGN(4); . = ALIGN(4);
_erelocate = .; _erelocate = .;
} > ram AT> rom } > ram AT> rom

View File

@ -6,7 +6,6 @@ include $(RIOTCPU)/mips32r2_common/Makefile.include
CFLAGS += -D_SYS__PTHREADTYPES_H_ CFLAGS += -D_SYS__PTHREADTYPES_H_
CFLAGS += -DCPU_FAM_$(call uppercase_and_underscore,$(CPU_FAM)) CFLAGS += -DCPU_FAM_$(call uppercase_and_underscore,$(CPU_FAM))
LINKFLAGS += -L$(RIOTCPU)/mips_pic32_common/ldscripts
INCLUDES += -I$(RIOTCPU)/mips_pic32_common/include INCLUDES += -I$(RIOTCPU)/mips_pic32_common/include
DIRS += $(RIOTCPU)/$(CPU)/$(CPU_MODEL) DIRS += $(RIOTCPU)/$(CPU)/$(CPU_MODEL)

View File

@ -0,0 +1,21 @@
SECTIONS
{
.data :
{
KEEP (*(SORT(.xfa.*)))
}
_fdata = ADDR(.data);
_edata = (_fdata + SIZEOF(.data));
}
INSERT BEFORE .sbss;
SECTIONS
{
.rodata :
{
KEEP (*(SORT(.roxfa.*)))
}
}
INSERT AFTER .dtors;

View File

@ -0,0 +1,24 @@
SECTIONS
{
.rodata :
{
KEEP (*(SORT(.roxfa.*)))
} > ROM
}
INSERT AFTER .rodata;
SECTIONS
{
.data :
{
KEEP (*(SORT(.xfa.*)))
} > RAM AT> ROM
. = ALIGN(2);
_edata = .;
PROVIDE (edata = .);
PROVIDE (__dataend = .);
}
INSERT AFTER .data;

View File

@ -0,0 +1,19 @@
SECTIONS
{
.data :
{
KEEP (*(SORT(.xfa.*)))
}
}
INSERT AFTER .text;
SECTIONS
{
.rodata :
{
KEEP (*(SORT(.roxfa.*)))
}
}
INSERT AFTER .text;

View File

@ -61,6 +61,7 @@ SECTIONS
*(.rdata) *(.rdata)
*(.rodata .rodata.*) *(.rodata .rodata.*)
*(.gnu.linkonce.r.*) *(.gnu.linkonce.r.*)
KEEP (*(SORT(.roxfa.*)))
} >flash AT>flash :flash } >flash AT>flash :flash
. = ALIGN(4); . = ALIGN(4);
@ -182,6 +183,7 @@ SECTIONS
*(.srodata.cst4) *(.srodata.cst4)
*(.srodata.cst2) *(.srodata.cst2)
*(.srodata .srodata.*) *(.srodata .srodata.*)
KEEP (*(SORT(.xfa.*)))
} >ram AT>flash :ram_init } >ram AT>flash :ram_init
. = ALIGN(4); . = ALIGN(4);

View File

@ -9,8 +9,11 @@ CFLAGS_OPT ?= -Os
CFLAGS += $(CFLAGS_CPU) $(CFLAGS_LINK) $(CFLAGS_DBG) $(CFLAGS_OPT) CFLAGS += $(CFLAGS_CPU) $(CFLAGS_LINK) $(CFLAGS_DBG) $(CFLAGS_OPT)
ASFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) ASFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG)
# needed for xfa support. Order is important.
LINKFLAGS += -T$(RIOTCPU)/atmega_common/ldscripts/xfa.ld
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) -static -lgcc -e reset_handler -Wl,--gc-sections LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) -static -lgcc -e reset_handler -Wl,--gc-sections
OFLAGS += -j .text -j .data
# Use ROM_LEN and RAM_LEN during link # Use ROM_LEN and RAM_LEN during link
$(if $(ROM_LEN),,$(error ROM_LEN is not defined)) $(if $(ROM_LEN),,$(error ROM_LEN is not defined))

View File

@ -64,6 +64,9 @@ LINKFLAGS += -L$(RIOTCPU)/$(CPU)/ldscripts
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT)
LINKFLAGS += -Wl,--gc-sections LINKFLAGS += -Wl,--gc-sections
# XFA support
LINKFLAGS += -T$(RIOTCPU)/mips_pic32_common/ldscripts/xfa.ld
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation
OPTIONAL_CFLAGS_BLACKLIST += -gz OPTIONAL_CFLAGS_BLACKLIST += -gz

View File

@ -15,6 +15,8 @@ ASFLAGS += $(CFLAGS_CPU) --defsym $(CPU_MODEL)=1 $(CFLAGS_DBG)
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT)
LINKFLAGS += -Wl,--gc-sections -Wl,-L$(MSP430_SUPPORT_FILES)/include LINKFLAGS += -Wl,--gc-sections -Wl,-L$(MSP430_SUPPORT_FILES)/include
LINKFLAGS += -T $(MSP430_SUPPORT_FILES)/include/$(CPU_MODEL).ld
LINKFLAGS += $(RIOTCPU)/msp430_common/ldscripts/xfa.ld
OPTIONAL_CFLAGS_BLACKLIST += -fdiagnostics-color OPTIONAL_CFLAGS_BLACKLIST += -fdiagnostics-color
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2018 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @addtogroup unittests
* @{
*
* @file
* @brief Data elements for the core/xfa unit test
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#include "xfa.h"
#include "tests-core-xfa.h"
XFA(xfatest, 0) xfatest_t _xfatest1 = { .val = 12345, .text = "xfatest1" };
XFA_CONST(xfatest_const, 0) xfatest_t _xfatest_const1 = { .val = 0xcafe, .text = "xfatest_const1" };
XFA_INIT(xfatest_t, xfatest_use);
XFA_INIT_CONST(xfatest_t, xfatest_use_const);
XFA(xfatest_use, 0) xfatest_t _xfatest_use1 = { .val = 3333, .text = "xfatest_use1" };
XFA(xfatest_use, 0) xfatest_t _xfatest_use_again = { .val = 555, .text = "xfatest use again" };
XFA_CONST(xfatest_use_const, 0) xfatest_t _xfatest_use_const1 = { .val = 4444, .text = "xfatest_use_const1" };
int hack1;
/** @} */

View File

@ -0,0 +1,26 @@
/*
* Copyright (C) 2018 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @addtogroup unittests
* @{
*
* @file
* @brief Data elements for the core/xfa unit test
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#include "xfa.h"
#include "tests-core-xfa.h"
XFA(xfatest, 0) xfatest_t _xfatest2 = { .val = 0xbeef, .text = "another test string" };
XFA_CONST(xfatest_const, 0) xfatest_t _xfatest_const2 = { .val = 32444, .text = "const string xfa 2" };
XFA(xfatest_use, 0) xfatest_t _xfatest_use2 = { .val = 11111, .text = "xfatest_use2" };
XFA_CONST(xfatest_use_const, 0) xfatest_t _xfatest_use_const2 = { .val = 22222, .text = "xfatest_use_const2" };
/** @} */

View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2018 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <stdint.h>
#include "bitarithm.h"
#include "xfa.h"
#include "embUnit.h"
#include "tests-core.h"
#include "tests-core-xfa.h"
XFA_INIT(xfatest_t, xfatest);
XFA_INIT_CONST(xfatest_t, xfatest_const);
XFA_USE(xfatest_t, xfatest_use);
XFA_USE_CONST(xfatest_t, xfatest_use_const);
/* Verifying that cross file array linking is correct by iterating over an external array */
static void test_xfa_data(void)
{
unsigned n = XFA_LEN(xfatest_t, xfatest);
TEST_ASSERT_EQUAL_INT(2, n);
unsigned found = 0;
for (unsigned k = 0; k < n; ++k) {
/* we do not want to enforce the order of the data elements */
switch (xfatest[k].val) {
case 12345:
/* tests-core-xfa-data1.c */
TEST_ASSERT_EQUAL_STRING("xfatest1", xfatest[k].text);
TEST_ASSERT(!(found & BIT0));
found |= BIT0;
break;
case 0xbeef:
/* tests-core-xfa-data2.c */
TEST_ASSERT_EQUAL_STRING("another test string", xfatest[k].text);
TEST_ASSERT(!(found & BIT1));
found |= BIT1;
break;
default:
break;
}
}
TEST_ASSERT_EQUAL_INT((1U << n) - 1, found);
}
static void test_xfa_const_data(void)
{
unsigned n = XFA_LEN(xfatest_t, xfatest_const);
TEST_ASSERT_EQUAL_INT(2, n);
unsigned found = 0;
for (unsigned k = 0; k < n; ++k) {
/* we do not want to enforce the order of the data elements */
switch (xfatest_const[k].val) {
case 0xcafe:
/* tests-core-xfa-data1.c */
TEST_ASSERT_EQUAL_STRING("xfatest_const1", xfatest_const[k].text);
++found;
break;
case 32444:
/* tests-core-xfa-data2.c */
TEST_ASSERT_EQUAL_STRING("const string xfa 2", xfatest_const[k].text);
++found;
break;
default:
break;
}
}
TEST_ASSERT_EQUAL_INT(n, found);
}
static void test_xfa_use_data(void)
{
unsigned n = XFA_LEN(xfatest_t, xfatest_use);
TEST_ASSERT_EQUAL_INT(3, n);
unsigned found = 0;
for (unsigned k = 0; k < n; ++k) {
/* we do not want to enforce the order of the data elements */
switch (xfatest_use[k].val) {
case 3333:
/* tests-core-xfa-data1.c */
TEST_ASSERT_EQUAL_STRING("xfatest_use1", xfatest_use[k].text);
++found;
break;
case 555:
/* tests-core-xfa-data1.c */
TEST_ASSERT_EQUAL_STRING("xfatest use again", xfatest_use[k].text);
++found;
break;
case 11111:
/* tests-core-xfa-data2.c */
TEST_ASSERT_EQUAL_STRING("xfatest_use2", xfatest_use[k].text);
++found;
break;
default:
break;
}
}
TEST_ASSERT_EQUAL_INT(n, found);
}
static void test_xfa_use_const_data(void)
{
unsigned n = XFA_LEN(xfatest_t, xfatest_use_const);
TEST_ASSERT_EQUAL_INT(2, n);
unsigned found = 0;
for (unsigned k = 0; k < n; ++k) {
/* we do not want to enforce the order of the data elements */
switch (xfatest_use_const[k].val) {
case 4444:
/* tests-core-xfa-data1.c */
TEST_ASSERT_EQUAL_STRING("xfatest_use_const1", xfatest_use_const[k].text);
++found;
break;
case 22222:
/* tests-core-xfa-data2.c */
TEST_ASSERT_EQUAL_STRING("xfatest_use_const2", xfatest_use_const[k].text);
++found;
break;
default:
break;
}
}
TEST_ASSERT_EQUAL_INT(n, found);
}
Test *tests_core_xfa_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_xfa_data),
new_TestFixture(test_xfa_const_data),
new_TestFixture(test_xfa_use_data),
new_TestFixture(test_xfa_use_const_data),
};
EMB_UNIT_TESTCALLER(core_xfa_tests, NULL, NULL,
fixtures);
return (Test *)&core_xfa_tests;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2018 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @addtogroup unittests
* @{
*
* @file
* @brief Declarations for the core/xfa unit test
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef TESTS_CORE_XFA_H
#define TESTS_CORE_XFA_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned val;
const char *text;
} xfatest_t;
#ifdef __cplusplus
}
#endif
#endif /* TESTS_CORE_XFA_H */
/** @} */

View File

@ -19,4 +19,5 @@ void tests_core(void)
TESTS_RUN(tests_core_priority_queue_tests()); TESTS_RUN(tests_core_priority_queue_tests());
TESTS_RUN(tests_core_byteorder_tests()); TESTS_RUN(tests_core_byteorder_tests());
TESTS_RUN(tests_core_ringbuffer_tests()); TESTS_RUN(tests_core_ringbuffer_tests());
TESTS_RUN(tests_core_xfa_tests());
} }

View File

@ -92,6 +92,13 @@ Test *tests_core_byteorder_tests(void);
*/ */
Test *tests_core_ringbuffer_tests(void); Test *tests_core_ringbuffer_tests(void);
/**
* @brief Generates tests for xfa.h
*
* @return embUnit tests if successful, NULL if not.
*/
Test *tests_core_xfa_tests(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

12
tests/xfa/Makefile Normal file
View File

@ -0,0 +1,12 @@
include ../Makefile.tests_common
include $(RIOTBASE)/Makefile.include
all: static-test
static-test: $(ELFFILE)
$(Q)TEST_STARTADDR=$$($(OBJDUMP) -t $< | grep -E '\sxfatest_const$$' | awk '{ printf "0x%s", $$1}'); \
TEST_ENDADDR=$$($(OBJDUMP) -t $< | grep -E '\sxfatest_const_end$$' | awk '{ printf "0x%s", $$1}'); \
if test ! $$((TEST_STARTADDR)) -lt $$((TEST_ENDADDR)); then \
echo "Error: Static check of XFA linked const array failed, verify linker flags and try again" >&2; \
exit 1; \
fi

47
tests/xfa/main.c Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup test
* @{
*
* @file
* @brief cross file array (XFA) test application
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>
#include "xfa.h"
#include "xfatest.h"
XFA_INIT(xfatest_t, xfatest);
XFA_INIT_CONST(xfatest_t, xfatest_const);
int main(void)
{
puts("Cross file array test");
unsigned n = XFA_LEN(xfatest_t, xfatest);
printf("xfatest[%u]:\n", n);
for (unsigned i = 0; i < n; i++) {
printf("[%u] = %u, \"%s\"\n", i, xfatest[i].val, xfatest[i].text);
}
n = XFA_LEN(xfatest_t, xfatest_const);
printf("xfatest_const[%u]:\n", n);
for (unsigned i = 0; i < n; i++) {
printf("[%u] = %u, \"%s\"\n", i, xfatest_const[i].val, xfatest_const[i].text);
}
return 0;
}

26
tests/xfa/tests/01-run.py Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env python3
# Copyright (C) 2021 Freie Universität Berlin
# 2021 Inria
# 2021 Kaspar Schleiser <kaspar@schleiser.de>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import sys
from testrunner import run
def testfunc(child):
child.expect_exact('Cross file array test')
child.expect_exact('xfatest[2]:')
child.expect_exact('[0] = 1, "xfatest1"')
child.expect_exact('[1] = 2, "xfatest2"')
child.expect_exact('xfatest_const[2]:')
child.expect_exact('[0] = 123, "xfatest_const1"')
child.expect_exact('[1] = 45, "xfatest_const2"')
if __name__ == "__main__":
sys.exit(run(testfunc))

29
tests/xfa/xfatest.h Normal file
View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef XFATEST_H
#define XFATEST_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef DOXYGEN /* just a test header, please ignore */
typedef struct {
unsigned val;
const char *text;
} xfatest_t;
#endif /* DOXYGEN */
#ifdef __cplusplus
}
#endif
#endif /* XFATEST_H */

5
tests/xfa/xfatest1.c Normal file
View File

@ -0,0 +1,5 @@
#include "xfa.h"
#include "xfatest.h"
XFA(xfatest, 0) xfatest_t _xfatest1 = { .val = 1, .text = "xfatest1" };
XFA_CONST(xfatest_const, 0) xfatest_t _xfatest_const1 = { .val = 123, .text = "xfatest_const1" };

5
tests/xfa/xfatest2.c Normal file
View File

@ -0,0 +1,5 @@
#include "xfa.h"
#include "xfatest.h"
XFA(xfatest, 0) xfatest_t _xfatest2 = { .val = 2, .text = "xfatest2" };
XFA_CONST(xfatest_const, 0) xfatest_t _xfatest_const2 = { .val = 45, .text = "xfatest_const2" };