|
| 1 | +/** |
| 2 | + * @file incbin.h |
| 3 | + * @author Dale Weiler |
| 4 | + * @brief Utility for including binary files |
| 5 | + * |
| 6 | + * Facilities for including binary files into the current translation unit and |
| 7 | + * making use from them externally in other translation units. |
| 8 | + */ |
| 9 | +#ifndef INCBIN_HDR |
| 10 | +#define INCBIN_HDR |
| 11 | +#include <limits.h> |
| 12 | +#if defined(__AVX512BW__) || \ |
| 13 | + defined(__AVX512CD__) || \ |
| 14 | + defined(__AVX512DQ__) || \ |
| 15 | + defined(__AVX512ER__) || \ |
| 16 | + defined(__AVX512PF__) || \ |
| 17 | + defined(__AVX512VL__) || \ |
| 18 | + defined(__AVX512F__) |
| 19 | +# define INCBIN_ALIGNMENT_INDEX 6 |
| 20 | +#elif defined(__AVX__) || \ |
| 21 | + defined(__AVX2__) |
| 22 | +# define INCBIN_ALIGNMENT_INDEX 5 |
| 23 | +#elif defined(__SSE__) || \ |
| 24 | + defined(__SSE2__) || \ |
| 25 | + defined(__SSE3__) || \ |
| 26 | + defined(__SSSE3__) || \ |
| 27 | + defined(__SSE4_1__) || \ |
| 28 | + defined(__SSE4_2__) || \ |
| 29 | + defined(__neon__) |
| 30 | +# define INCBIN_ALIGNMENT_INDEX 4 |
| 31 | +#elif ULONG_MAX != 0xffffffffu |
| 32 | +# define INCBIN_ALIGNMENT_INDEX 3 |
| 33 | +# else |
| 34 | +# define INCBIN_ALIGNMENT_INDEX 2 |
| 35 | +#endif |
| 36 | + |
| 37 | +/* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */ |
| 38 | +#define INCBIN_ALIGN_SHIFT_0 1 |
| 39 | +#define INCBIN_ALIGN_SHIFT_1 2 |
| 40 | +#define INCBIN_ALIGN_SHIFT_2 4 |
| 41 | +#define INCBIN_ALIGN_SHIFT_3 8 |
| 42 | +#define INCBIN_ALIGN_SHIFT_4 16 |
| 43 | +#define INCBIN_ALIGN_SHIFT_5 32 |
| 44 | +#define INCBIN_ALIGN_SHIFT_6 64 |
| 45 | + |
| 46 | +/* Actual alignment value */ |
| 47 | +#define INCBIN_ALIGNMENT \ |
| 48 | + INCBIN_CONCATENATE( \ |
| 49 | + INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \ |
| 50 | + INCBIN_ALIGNMENT_INDEX) |
| 51 | + |
| 52 | +/* Stringize */ |
| 53 | +#define INCBIN_STR(X) \ |
| 54 | + #X |
| 55 | +#define INCBIN_STRINGIZE(X) \ |
| 56 | + INCBIN_STR(X) |
| 57 | +/* Concatenate */ |
| 58 | +#define INCBIN_CAT(X, Y) \ |
| 59 | + X ## Y |
| 60 | +#define INCBIN_CONCATENATE(X, Y) \ |
| 61 | + INCBIN_CAT(X, Y) |
| 62 | +/* Deferred macro expansion */ |
| 63 | +#define INCBIN_EVAL(X) \ |
| 64 | + X |
| 65 | +#define INCBIN_INVOKE(N, ...) \ |
| 66 | + INCBIN_EVAL(N(__VA_ARGS__)) |
| 67 | + |
| 68 | +/* Green Hills uses a different directive for including binary data */ |
| 69 | +#if defined(__ghs__) |
| 70 | +# if (__ghs_asm == 2) |
| 71 | +# define INCBIN_MACRO ".file" |
| 72 | +/* Or consider the ".myrawdata" entry in the ld file */ |
| 73 | +# else |
| 74 | +# define INCBIN_MACRO "\tINCBIN" |
| 75 | +# endif |
| 76 | +#else |
| 77 | +# define INCBIN_MACRO ".incbin" |
| 78 | +#endif |
| 79 | + |
| 80 | +#ifndef _MSC_VER |
| 81 | +# define INCBIN_ALIGN \ |
| 82 | + __attribute__((aligned(INCBIN_ALIGNMENT))) |
| 83 | +#else |
| 84 | +# define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT)) |
| 85 | +#endif |
| 86 | + |
| 87 | +#if defined(__arm__) || /* GNU C and RealView */ \ |
| 88 | + defined(__arm) || /* Diab */ \ |
| 89 | + defined(_ARM) /* ImageCraft */ |
| 90 | +# define INCBIN_ARM |
| 91 | +#endif |
| 92 | + |
| 93 | +#ifdef __GNUC__ |
| 94 | +/* Utilize .balign where supported */ |
| 95 | +# define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" |
| 96 | +# define INCBIN_ALIGN_BYTE ".balign 1\n" |
| 97 | +#elif defined(INCBIN_ARM) |
| 98 | +/* |
| 99 | + * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is |
| 100 | + * the shift count. This is the value passed to `.align' |
| 101 | + */ |
| 102 | +# define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n" |
| 103 | +# define INCBIN_ALIGN_BYTE ".align 0\n" |
| 104 | +#else |
| 105 | +/* We assume other inline assembler's treat `.align' as `.balign' */ |
| 106 | +# define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" |
| 107 | +# define INCBIN_ALIGN_BYTE ".align 1\n" |
| 108 | +#endif |
| 109 | + |
| 110 | +/* INCBIN_CONST is used by incbin.c generated files */ |
| 111 | +#if defined(__cplusplus) |
| 112 | +# define INCBIN_EXTERNAL extern "C" |
| 113 | +# define INCBIN_CONST extern const |
| 114 | +#else |
| 115 | +# define INCBIN_EXTERNAL extern |
| 116 | +# define INCBIN_CONST const |
| 117 | +#endif |
| 118 | + |
| 119 | +/** |
| 120 | + * @brief Optionally override the linker section into which data is emitted. |
| 121 | + * |
| 122 | + * @warning If you use this facility, you'll have to deal with platform-specific linker output |
| 123 | + * section naming on your own |
| 124 | + * |
| 125 | + * Overriding the default linker output section, e.g for esp8266/Arduino: |
| 126 | + * @code |
| 127 | + * #define INCBIN_OUTPUT_SECTION ".irom.text" |
| 128 | + * #include "incbin.h" |
| 129 | + * INCBIN(Foo, "foo.txt"); |
| 130 | + * // Data is emitted into program memory that never gets copied to RAM |
| 131 | + * @endcode |
| 132 | + */ |
| 133 | +#if !defined(INCBIN_OUTPUT_SECTION) |
| 134 | +# if defined(__APPLE__) |
| 135 | +# define INCBIN_OUTPUT_SECTION ".const_data" |
| 136 | +# else |
| 137 | +# define INCBIN_OUTPUT_SECTION ".rodata" |
| 138 | +# endif |
| 139 | +#endif |
| 140 | + |
| 141 | +#if defined(__APPLE__) |
| 142 | +/* The directives are different for Apple branded compilers */ |
| 143 | +# define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n" |
| 144 | +# define INCBIN_GLOBAL(NAME) ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" |
| 145 | +# define INCBIN_INT ".long " |
| 146 | +# define INCBIN_MANGLE "_" |
| 147 | +# define INCBIN_BYTE ".byte " |
| 148 | +# define INCBIN_TYPE(...) |
| 149 | +#else |
| 150 | +# define INCBIN_SECTION ".section " INCBIN_OUTPUT_SECTION "\n" |
| 151 | +# define INCBIN_GLOBAL(NAME) ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" |
| 152 | +# if defined(__ghs__) |
| 153 | +# define INCBIN_INT ".word " |
| 154 | +# else |
| 155 | +# define INCBIN_INT ".int " |
| 156 | +# endif |
| 157 | +# if defined(__USER_LABEL_PREFIX__) |
| 158 | +# define INCBIN_MANGLE INCBIN_STRINGIZE(__USER_LABEL_PREFIX__) |
| 159 | +# else |
| 160 | +# define INCBIN_MANGLE "" |
| 161 | +# endif |
| 162 | +# if defined(INCBIN_ARM) |
| 163 | +/* On arm assemblers, `@' is used as a line comment token */ |
| 164 | +# define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n" |
| 165 | +# elif defined(__MINGW32__) || defined(__MINGW64__) |
| 166 | +/* Mingw doesn't support this directive either */ |
| 167 | +# define INCBIN_TYPE(NAME) |
| 168 | +# else |
| 169 | +/* It's safe to use `@' on other architectures */ |
| 170 | +# define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n" |
| 171 | +# endif |
| 172 | +# define INCBIN_BYTE ".byte " |
| 173 | +#endif |
| 174 | + |
| 175 | +/* List of style types used for symbol names */ |
| 176 | +#define INCBIN_STYLE_CAMEL 0 |
| 177 | +#define INCBIN_STYLE_SNAKE 1 |
| 178 | + |
| 179 | +/** |
| 180 | + * @brief Specify the prefix to use for symbol names. |
| 181 | + * |
| 182 | + * By default this is `g', producing symbols of the form: |
| 183 | + * @code |
| 184 | + * #include "incbin.h" |
| 185 | + * INCBIN(Foo, "foo.txt"); |
| 186 | + * |
| 187 | + * // Now you have the following symbols: |
| 188 | + * // const unsigned char gFooData[]; |
| 189 | + * // const unsigned char *const gFooEnd; |
| 190 | + * // const unsigned int gFooSize; |
| 191 | + * @endcode |
| 192 | + * |
| 193 | + * If however you specify a prefix before including: e.g: |
| 194 | + * @code |
| 195 | + * #define INCBIN_PREFIX incbin |
| 196 | + * #include "incbin.h" |
| 197 | + * INCBIN(Foo, "foo.txt"); |
| 198 | + * |
| 199 | + * // Now you have the following symbols instead: |
| 200 | + * // const unsigned char incbinFooData[]; |
| 201 | + * // const unsigned char *const incbinFooEnd; |
| 202 | + * // const unsigned int incbinFooSize; |
| 203 | + * @endcode |
| 204 | + */ |
| 205 | +#if !defined(INCBIN_PREFIX) |
| 206 | +# define INCBIN_PREFIX g |
| 207 | +#endif |
| 208 | + |
| 209 | +/** |
| 210 | + * @brief Specify the style used for symbol names. |
| 211 | + * |
| 212 | + * Possible options are |
| 213 | + * - INCBIN_STYLE_CAMEL "CamelCase" |
| 214 | + * - INCBIN_STYLE_SNAKE "snake_case" |
| 215 | + * |
| 216 | + * Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form: |
| 217 | + * @code |
| 218 | + * #include "incbin.h" |
| 219 | + * INCBIN(Foo, "foo.txt"); |
| 220 | + * |
| 221 | + * // Now you have the following symbols: |
| 222 | + * // const unsigned char <prefix>FooData[]; |
| 223 | + * // const unsigned char *const <prefix>FooEnd; |
| 224 | + * // const unsigned int <prefix>FooSize; |
| 225 | + * @endcode |
| 226 | + * |
| 227 | + * If however you specify a style before including: e.g: |
| 228 | + * @code |
| 229 | + * #define INCBIN_STYLE INCBIN_STYLE_SNAKE |
| 230 | + * #include "incbin.h" |
| 231 | + * INCBIN(foo, "foo.txt"); |
| 232 | + * |
| 233 | + * // Now you have the following symbols: |
| 234 | + * // const unsigned char <prefix>foo_data[]; |
| 235 | + * // const unsigned char *const <prefix>foo_end; |
| 236 | + * // const unsigned int <prefix>foo_size; |
| 237 | + * @endcode |
| 238 | + */ |
| 239 | +#if !defined(INCBIN_STYLE) |
| 240 | +# define INCBIN_STYLE INCBIN_STYLE_CAMEL |
| 241 | +#endif |
| 242 | + |
| 243 | +/* Style lookup tables */ |
| 244 | +#define INCBIN_STYLE_0_DATA Data |
| 245 | +#define INCBIN_STYLE_0_END End |
| 246 | +#define INCBIN_STYLE_0_SIZE Size |
| 247 | +#define INCBIN_STYLE_1_DATA _data |
| 248 | +#define INCBIN_STYLE_1_END _end |
| 249 | +#define INCBIN_STYLE_1_SIZE _size |
| 250 | + |
| 251 | +/* Style lookup: returning identifier */ |
| 252 | +#define INCBIN_STYLE_IDENT(TYPE) \ |
| 253 | + INCBIN_CONCATENATE( \ |
| 254 | + INCBIN_STYLE_, \ |
| 255 | + INCBIN_CONCATENATE( \ |
| 256 | + INCBIN_EVAL(INCBIN_STYLE), \ |
| 257 | + INCBIN_CONCATENATE(_, TYPE))) |
| 258 | + |
| 259 | +/* Style lookup: returning string literal */ |
| 260 | +#define INCBIN_STYLE_STRING(TYPE) \ |
| 261 | + INCBIN_STRINGIZE( \ |
| 262 | + INCBIN_STYLE_IDENT(TYPE)) \ |
| 263 | + |
| 264 | +/* Generate the global labels by indirectly invoking the macro with our style |
| 265 | + * type and concatenating the name against them. */ |
| 266 | +#define INCBIN_GLOBAL_LABELS(NAME, TYPE) \ |
| 267 | + INCBIN_INVOKE( \ |
| 268 | + INCBIN_GLOBAL, \ |
| 269 | + INCBIN_CONCATENATE( \ |
| 270 | + NAME, \ |
| 271 | + INCBIN_INVOKE( \ |
| 272 | + INCBIN_STYLE_IDENT, \ |
| 273 | + TYPE))) \ |
| 274 | + INCBIN_INVOKE( \ |
| 275 | + INCBIN_TYPE, \ |
| 276 | + INCBIN_CONCATENATE( \ |
| 277 | + NAME, \ |
| 278 | + INCBIN_INVOKE( \ |
| 279 | + INCBIN_STYLE_IDENT, \ |
| 280 | + TYPE))) |
| 281 | + |
| 282 | +/** |
| 283 | + * @brief Externally reference binary data included in another translation unit. |
| 284 | + * |
| 285 | + * Produces three external symbols that reference the binary data included in |
| 286 | + * another translation unit. |
| 287 | + * |
| 288 | + * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with |
| 289 | + * "Data", as well as "End" and "Size" after. An example is provided below. |
| 290 | + * |
| 291 | + * @param NAME The name given for the binary data |
| 292 | + * |
| 293 | + * @code |
| 294 | + * INCBIN_EXTERN(Foo); |
| 295 | + * |
| 296 | + * // Now you have the following symbols: |
| 297 | + * // extern const unsigned char <prefix>FooData[]; |
| 298 | + * // extern const unsigned char *const <prefix>FooEnd; |
| 299 | + * // extern const unsigned int <prefix>FooSize; |
| 300 | + * @endcode |
| 301 | + */ |
| 302 | +#define INCBIN_EXTERN(NAME) \ |
| 303 | + INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \ |
| 304 | + INCBIN_CONCATENATE( \ |
| 305 | + INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ |
| 306 | + INCBIN_STYLE_IDENT(DATA))[]; \ |
| 307 | + INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \ |
| 308 | + INCBIN_CONCATENATE( \ |
| 309 | + INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ |
| 310 | + INCBIN_STYLE_IDENT(END)); \ |
| 311 | + INCBIN_EXTERNAL const unsigned int \ |
| 312 | + INCBIN_CONCATENATE( \ |
| 313 | + INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ |
| 314 | + INCBIN_STYLE_IDENT(SIZE)) |
| 315 | + |
| 316 | +/** |
| 317 | + * @brief Include a binary file into the current translation unit. |
| 318 | + * |
| 319 | + * Includes a binary file into the current translation unit, producing three symbols |
| 320 | + * for objects that encode the data and size respectively. |
| 321 | + * |
| 322 | + * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with |
| 323 | + * "Data", as well as "End" and "Size" after. An example is provided below. |
| 324 | + * |
| 325 | + * @param NAME The name to associate with this binary data (as an identifier.) |
| 326 | + * @param FILENAME The file to include (as a string literal.) |
| 327 | + * |
| 328 | + * @code |
| 329 | + * INCBIN(Icon, "icon.png"); |
| 330 | + * |
| 331 | + * // Now you have the following symbols: |
| 332 | + * // const unsigned char <prefix>IconData[]; |
| 333 | + * // const unsigned char *const <prefix>IconEnd; |
| 334 | + * // const unsigned int <prefix>IconSize; |
| 335 | + * @endcode |
| 336 | + * |
| 337 | + * @warning This must be used in global scope |
| 338 | + * @warning The identifiers may be different if INCBIN_STYLE is not default |
| 339 | + * |
| 340 | + * To externally reference the data included by this in another translation unit |
| 341 | + * please @see INCBIN_EXTERN. |
| 342 | + */ |
| 343 | +#ifdef _MSC_VER |
| 344 | +#define INCBIN(NAME, FILENAME) \ |
| 345 | + INCBIN_EXTERN(NAME) |
| 346 | +#else |
| 347 | +#define INCBIN(NAME, FILENAME) \ |
| 348 | + __asm__(INCBIN_SECTION \ |
| 349 | + INCBIN_GLOBAL_LABELS(NAME, DATA) \ |
| 350 | + INCBIN_ALIGN_HOST \ |
| 351 | + INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \ |
| 352 | + INCBIN_MACRO " \"" FILENAME "\"\n" \ |
| 353 | + INCBIN_GLOBAL_LABELS(NAME, END) \ |
| 354 | + INCBIN_ALIGN_BYTE \ |
| 355 | + INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \ |
| 356 | + INCBIN_BYTE "1\n" \ |
| 357 | + INCBIN_GLOBAL_LABELS(NAME, SIZE) \ |
| 358 | + INCBIN_ALIGN_HOST \ |
| 359 | + INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" \ |
| 360 | + INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " \ |
| 361 | + INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) "\n" \ |
| 362 | + INCBIN_ALIGN_HOST \ |
| 363 | + ".text\n" \ |
| 364 | + ); \ |
| 365 | + INCBIN_EXTERN(NAME) |
| 366 | + |
| 367 | +#endif |
| 368 | +#endif |
0 commit comments