graphitemaster / incbin

Include binary files in C/C++
The Unlicense
938 stars 87 forks source link

.type directive not supported in cross-compile #24

Closed JasonWoof closed 6 years ago

JasonWoof commented 7 years ago

Thanks for INCBIN! Before I found your tool I was trying to do this method myself, and was struggling to get it to link while cross-compiling. I am hopefull that this tool will also make it easier for me to make mac builds when the time comes.

When I used the latest incbin.h, I got this error when cross-compiling using the MXE cross compile on a linux host:

$ /home/jasonwoof/software/mxe/usr/bin/i686-w64-mingw32.static-gcc -c -o test.o test.c
/tmp/cca2SpPv.s: Assembler messages:
/tmp/cca2SpPv.s:5: Warning: .type pseudo-op used outside of .def/.endef ignored.
/tmp/cca2SpPv.s:5: Error: junk at end of line, first unrecognized character is `b'
/tmp/cca2SpPv.s:10: Warning: .type pseudo-op used outside of .def/.endef ignored.
/tmp/cca2SpPv.s:10: Error: junk at end of line, first unrecognized character is `b'
/tmp/cca2SpPv.s:15: Warning: .type pseudo-op used outside of .def/.endef ignored.
/tmp/cca2SpPv.s:15: Error: junk at end of line, first unrecognized character is `b'
zsh: exit 1     /home/jasonwoof/software/mxe/usr/bin/i686-w64-mingw32.static-gcc -c -o test.o

$ cat test.c
#include <stdio.h>
#define INCBIN_STYLE INCBIN_STYLE_SNAKE
#define INCBIN_PREFIX binary_
#include "incbin.h"
INCBIN(game_js, "game.js");

int
main(int argc, char **argv) {
    printf("%s, %0d\n",
        binary_game_js_data,
        binary_game_js_size
    );
    return 0;
}

As a workaround, I commented out the .type asm directive like this:

/* It's safe to use `@' on other architectures */
#    define INCBIN_TYPE(NAME)    "#.type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n"

Then my test compiles and runs perfectly (built on linux, tested with wine) and also compiles and runs fine an/for native linux.

graphitemaster commented 7 years ago

is there a way to determine this compiler, we would put an ifdef and simply not have INCBIN_TYPE resolve to anything

graphitemaster commented 7 years ago

Looks like it's just mingw?

JasonWoof commented 7 years ago

I think it's a pretty vanilla mingw. MXE is a sort of sorce-based package manager that has configurations for compining mingw and lots of static libs.

A quick web search revealed this: #if defined(__MINGW32__) || defined(__MINGW64__) along with a suggestion that they set __MINGW__ if either is set. I tested all three on my environment and found only __MINGW32__ was defined.

This patch works for me both when compiling for native linux, and when cross compiling for win:

diff --git a/incbin.h b/incbin.h
index 7196f96..510c936 100644
--- a/incbin.h
+++ b/incbin.h
@@ -118,6 +118,9 @@
 #  if defined(INCBIN_ARM)
 /* On arm assemblers, `@' is used as a line comment token */
 #    define INCBIN_TYPE(NAME)    ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n"
+#  elif defined(__MINGW32__) || defined(__MINGW64__)
+/* Minw doesn't support this directive either */
+#    define INCBIN_TYPE(...)
 #  else
 /* It's safe to use `@' on other architectures */
 #    define INCBIN_TYPE(NAME)    ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n"
graphitemaster commented 7 years ago

This is interesting because mingw is one of the toolchains that incbin does not support but should now be capable of supporting. I've been trying to set one up to test the patch and I can't really get it to work so I'll take your word.

graphitemaster commented 7 years ago

Looking into this a bit more and it seems that the way mingw works is you h ave to use a .def and .enddef pair to use the .type (which takes an integer) along with .scl (storage class specifier). The reason we want these at all in incbin is because this is how you get debug symbols. This may be difficult to do ;)

graphitemaster commented 7 years ago

Now here in lies the problem, that type is part of the COFF format which is really confusing to grasp because it actually has specific object types unlike @object so if we want to specify long int (as we do for size) then the e_type bit pattern for that is DT_NON | T_LONG << N_BTSHIFT. Then for our array of unsigned characters that is DT_ARY | T_UCHAR << N_BTSHIFT Which means we now need two variants. We also have some pointers to the end of the array too so that is DT_PTR| T_UCHAR << N_BTSHIFT, so in total we need three variants to support mingw correctly: http://www.delorie.com/djgpp/doc/coff/symtab.html Contains all that information.

graphitemaster commented 7 years ago

The bit patterns are really confusing to me though as the first two bits appear to be never used

JasonWoof commented 7 years ago

I found MXE to be a very easy way to get mingw running: http://mxe.cc/

Also mingw is in debian main, and probably other distros too

JasonWoof commented 7 years ago

Or I can test for you. Just let me know

graphitemaster commented 6 years ago

Fixed this with your patch, debugging support will be suboptimal but the correct approach is even more difficult and not worth the added complexity.