Cross compiling DOS tool with Allegro 4.2 - multiple definitions during linking
megatron-uk

Hi,

I'm writing a cross-platform game browser tool, one of the platforms being DOS, and as such, am using Allegro 4.2 for the graphics handling on that platform (others being SDL for Linux, GEM/VDI for Atari ST, etc).

When I'm linking my code using liballeg.a I get loads of multiple definition errors:

#SelectExpand
1/usr/i586-pc-msdosdjgpp/bin/i586-pc-msdosdjgpp-gcc -Wall -Wno-unused-function -DUSE_LOGGING -DLOGGING -g -o bin/menu_dos.exe src/menu.o src/logging.o src/input.o src/image.o src/qdbmp.o src/gfx.o src/bmp2text.o src/csvlib.o src/gamedata.o -L/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/lib -lalleg 2 3src/gfx.o:gfx.c:(.text+0x0): multiple definition of `_default_ds' 4src/menu.o:menu.c:(.text+0x90): first defined here 5src/gfx.o:gfx.c:(.text+0x8): multiple definition of `bmp_write_line' 6src/menu.o:menu.c:(.text+0x98): first defined here 7src/gfx.o:gfx.c:(.text+0x18): multiple definition of `bmp_read_line' 8src/menu.o:menu.c:(.text+0xa8): first defined here 9src/gfx.o:gfx.c:(.text+0x28): multiple definition of `bmp_unwrite_line' 10src/menu.o:menu.c:(.text+0xb8): first defined here 11src/gfx.o:gfx.c:(.text+0x38): multiple definition of `is_windowed_mode' 12src/menu.o:menu.c:(.text+0xc8): first defined here 13src/gfx.o:gfx.c:(.text+0x44): multiple definition of `clear_to_color' 14src/menu.o:menu.c:(.text+0xd4): first defined here 15src/gfx.o:gfx.c:(.text+0x54): multiple definition of `bitmap_color_depth' 16src/menu.o:menu.c:(.text+0xe4): first defined here 17src/gfx.o:gfx.c:(.text+0x60): multiple definition of `bitmap_mask_color' 18src/menu.o:menu.c:(.text+0xf0): first defined here 19src/gfx.o:gfx.c:(.text+0x6c): multiple definition of `is_same_bitmap' 20src/menu.o:menu.c:(.text+0xfc): first defined here 21src/gfx.o:gfx.c:(.text+0xa8): multiple definition of `is_linear_bitmap' 22src/menu.o:menu.c:(.text+0x138): first defined here 23src/gfx.o:gfx.c:(.text+0xbc): multiple definition of `is_planar_bitmap' 24src/menu.o:menu.c:(.text+0x14c): first defined here 25src/gfx.o:gfx.c:(.text+0xcc): multiple definition of `is_memory_bitmap' 26src/menu.o:menu.c:(.text+0x15c): first defined here 27src/gfx.o:gfx.c:(.text+0xe0): multiple definition of `is_screen_bitmap' 28src/menu.o:menu.c:(.text+0x170): first defined here 29src/gfx.o:gfx.c:(.text+0x120): multiple definition of `is_video_bitmap' 30src/menu.o:menu.c:(.text+0x1b0): first defined here 31src/gfx.o:gfx.c:(.text+0x12c): multiple definition of `is_system_bitmap' 32src/menu.o:menu.c:(.text+0x1bc): first defined here 33src/gfx.o:gfx.c:(.text+0x13c): multiple definition of `is_sub_bitmap' 34src/menu.o:menu.c:(.text+0x1cc): first defined here 35src/gfx.o:gfx.c:(.text+0x14c): multiple definition of `acquire_bitmap' 36src/menu.o:menu.c:(.text+0x1dc): first defined here 37src/gfx.o:gfx.c:(.text+0x160): multiple definition of `release_bitmap' 38src/menu.o:menu.c:(.text+0x1f0): first defined here 39src/gfx.o:gfx.c:(.text+0x174): multiple definition of `acquire_screen' 40src/menu.o:menu.c:(.text+0x204): first defined here 41src/gfx.o:gfx.c:(.text+0x190): multiple definition of `release_screen' 42src/menu.o:menu.c:(.text+0x220): first defined here 43src/gfx.o:gfx.c:(.text+0x1ac): multiple definition of `is_inside_bitmap' 44src/menu.o:menu.c:(.text+0x23c): first defined here 45src/gfx.o:gfx.c:(.text+0x204): multiple definition of `get_clip_rect' 46src/menu.o:menu.c:(.text+0x294): first defined here 47src/gfx.o:gfx.c:(.text+0x234): multiple definition of `set_clip_state' 48src/menu.o:menu.c:(.text+0x2c4): first defined here 49src/gfx.o:gfx.c:(.text+0x240): multiple definition of `get_clip_state' 50src/menu.o:menu.c:(.text+0x2d0): first defined here 51src/bmp2text.o:bmp2text.c:(.text+0x0): multiple definition of `_default_ds' 52src/menu.o:menu.c:(.text+0x90): first defined here 53src/bmp2text.o:bmp2text.c:(.text+0x8): multiple definition of `bmp_write_line' 54src/menu.o:menu.c:(.text+0x98): first defined here 55src/bmp2text.o:bmp2text.c:(.text+0x18): multiple definition of `bmp_read_line' 56src/menu.o:menu.c:(.text+0xa8): first defined here 57src/bmp2text.o:bmp2text.c:(.text+0x28): multiple definition of `bmp_unwrite_line' 58src/menu.o:menu.c:(.text+0xb8): first defined here 59src/bmp2text.o:bmp2text.c:(.text+0x38): multiple definition of `is_windowed_mode' 60src/menu.o:menu.c:(.text+0xc8): first defined here 61src/bmp2text.o:bmp2text.c:(.text+0x44): multiple definition of `clear_to_color' 62src/menu.o:menu.c:(.text+0xd4): first defined here 63src/bmp2text.o:bmp2text.c:(.text+0x54): multiple definition of `bitmap_color_depth' 64src/menu.o:menu.c:(.text+0xe4): first defined here 65src/bmp2text.o:bmp2text.c:(.text+0x60): multiple definition of `bitmap_mask_color' 66src/menu.o:menu.c:(.text+0xf0): first defined here 67src/bmp2text.o:bmp2text.c:(.text+0x6c): multiple definition of `is_same_bitmap' 68src/menu.o:menu.c:(.text+0xfc): first defined here 69src/bmp2text.o:bmp2text.c:(.text+0xa8): multiple definition of `is_linear_bitmap' 70src/menu.o:menu.c:(.text+0x138): first defined here 71src/bmp2text.o:bmp2text.c:(.text+0xbc): multiple definition of `is_planar_bitmap' 72src/menu.o:menu.c:(.text+0x14c): first defined here 73src/bmp2text.o:bmp2text.c:(.text+0xcc): multiple definition of `is_memory_bitmap' 74src/menu.o:menu.c:(.text+0x15c): first defined here 75src/bmp2text.o:bmp2text.c:(.text+0xe0): multiple definition of `is_screen_bitmap' 76src/menu.o:menu.c:(.text+0x170): first defined here 77src/bmp2text.o:bmp2text.c:(.text+0x120): multiple definition of `is_video_bitmap' 78src/menu.o:menu.c:(.text+0x1b0): first defined here 79src/bmp2text.o:bmp2text.c:(.text+0x12c): multiple definition of `is_system_bitmap' 80src/menu.o:menu.c:(.text+0x1bc): first defined here 81src/bmp2text.o:bmp2text.c:(.text+0x13c): multiple definition of `is_sub_bitmap' 82src/menu.o:menu.c:(.text+0x1cc): first defined here 83src/bmp2text.o:bmp2text.c:(.text+0x14c): multiple definition of `acquire_bitmap' 84src/menu.o:menu.c:(.text+0x1dc): first defined here 85src/bmp2text.o:bmp2text.c:(.text+0x160): multiple definition of `release_bitmap' 86src/menu.o:menu.c:(.text+0x1f0): first defined here 87src/bmp2text.o:bmp2text.c:(.text+0x174): multiple definition of `acquire_screen' 88src/menu.o:menu.c:(.text+0x204): first defined here 89src/bmp2text.o:bmp2text.c:(.text+0x190): multiple definition of `release_screen' 90src/menu.o:menu.c:(.text+0x220): first defined here 91src/bmp2text.o:bmp2text.c:(.text+0x1ac): multiple definition of `is_inside_bitmap' 92src/menu.o:menu.c:(.text+0x23c): first defined here 93src/bmp2text.o:bmp2text.c:(.text+0x204): multiple definition of `get_clip_rect' 94src/menu.o:menu.c:(.text+0x294): first defined here 95src/bmp2text.o:bmp2text.c:(.text+0x234): multiple definition of `set_clip_state' 96src/menu.o:menu.c:(.text+0x2c4): first defined here 97src/bmp2text.o:bmp2text.c:(.text+0x240): multiple definition of `get_clip_state' 98src/menu.o:menu.c:(.text+0x2d0): first defined here 99collect2: error: ld returned 1 exit status 100Makefile.common:10: recipe for target 'menu_dos.exe' failed 101make: *** [menu_dos.exe] Error 1

I've got a couple of object files that do a #include <allegro/gfx.h> or #include <allegro/keyboard.h>, but why does this cause multiple definition errors?

Anyone else still using Allegro with more modern compilers for DOS? I've tried both GCC 5.5.0 and 7.2.0 as per (https://github.com/andrewwutw/build-djgpp/releases), but there's no difference in behaviour.

Allegro 4.2.2 is built for DOS from (https://github.com/msikma/allegro-4.2.2-xc).

It's years and years since I did any dabbling with Allegro - is the intention to only include any allegro headers only once, and in one place?

John

Edgar Reynaldo

Try defining ALLEGRO_STATICLINK before including allegro 4 or link to the dynamic library and see if it goes away.

megatron-uk

Thanks for the suggestion, unfortunately it doesn't appear to make any difference; both passing -DALLEGRO_STATICLINK to GCC, and also setting it manually around the include blocks for allegro.h:

#ifdef USE_ALLEGRO
#define ALLEGRO_STATICLINK
#include <allegro.h>
#endif

#SelectExpand
1/usr/i586-pc-msdosdjgpp/bin/i586-pc-msdosdjgpp-gcc -Wall -Wno-unused-function -Wno-unused-variable -march=i386 -mtune=i386 -mfpmath=387 -O3 -I/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/sys-include -DALLEGRO_STATICLINK -DUSE_ALLEGRO -DPOSIX -DDIR_SEP=\"\" -DGAMEDIR=\"C:\GAMES\" -DCSV_FILE=\"MENU.CSV\" -DALLEGRO_NO_COMPATIBILITY -DSTATICLINK=1 -DUSE_LOGGING -DLOGGING -c -o src/image.o src/image.c 2... 3[more objects compiling here] 4... 5/usr/i586-pc-msdosdjgpp/bin/i586-pc-msdosdjgpp-gcc -Wall -Wno-unused-function -Wno-unused-variable -march=i386 -mtune=i386 -mfpmath=387 -O3 -I/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/sys-include -DALLEGRO_STATICLINK -DUSE_ALLEGRO -DPOSIX -DDIR_SEP=\"\" -DGAMEDIR=\"C:\GAMES\" -DCSV_FILE=\"MENU.CSV\" -DALLEGRO_NO_COMPATIBILITY -DSTATICLINK=1 -DUSE_LOGGING -DLOGGING -c -o src/gamedata.o src/gamedata.c 6src/gamedata.c: In function 'comparegames': 7src/gamedata.c:254:6: warning: implicit declaration of function 'toupper' [-Wimplicit-function-declaration] 8 c = toupper(game_a->name[0]); 9 ^ 10 11Linking.... 12/usr/i586-pc-msdosdjgpp/bin/i586-pc-msdosdjgpp-gcc -Wall -Wno-unused-function -DUSE_LOGGING -DLOGGING -g -o bin/menu_dos.exe src/menu.o src/logging.o src/input.o src/image.o src/qdbmp.o src/gfx.o src/bmp2text.o src/csvlib.o src/gamedata.o -L/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/lib -lalleg 13src/input.o:input.c:(.text+0x0): multiple definition of `install_allegro' 14src/menu.o:menu.c:(.text+0x2d8): first defined here 15src/input.o:input.c:(.text+0x20): multiple definition of `set_window_title' 16src/menu.o:menu.c:(.text+0x2f8): first defined here 17src/input.o:input.c:(.text+0x34): multiple definition of `desktop_color_depth' 18src/menu.o:menu.c:(.text+0x30c): first defined here 19src/input.o:input.c:(.text+0x48): multiple definition of `get_desktop_resolution' 20... 21...

No joy.

I think the problem stems from having code in those allegro 4 header files, both in the inline headers in allegro/inline/*, but also in things like allegro/system.h (e.g. install_allegro is a function rather than just a prototype).

This makes me think I can't really use any part of Allegro unless it's in one, singular object file, am I right?

Edgar Reynaldo

No, thankfully that's not how allegro works. ;)

This is besides the point but you need to include the header for toupper, otherwise that function links to nothing. #include <ctype.h>

C will bite you like that.

When compiling statically, you also need to link to the following libraries :

-lkernel32
-luser32
-lgdi32
-lcomdlg32
-lole32
-ldinput
-lddraw
-ldxguid
-lwinmm
-ldsound

-static-libstdc++
-static-libgcc

But that won't get rid of the redefinition errors.

First, STATICLINK=1 is a flag passed to make when building allegro. If you're linking to liballeg.a, that is the dynamic allegro library, the static one would be liballeg_s.a, which you would link to with -lalleg_s. Since you're not doing that, don't define ALLEGRO_STATICLINK either. The problem is something else.

I'm trying to think what it is.

You might want to spend some time reading docs\build\mingw32.txt for some steps of the build process. They apply to DOS as well. You can get a .chm doc for 4.2.2 here :
https://download.tuxfamily.org/allegro/allegro-manual//4.2.2/allegro-manual-4.2.2.en.chm

Those are the latest docs for the 4.2.2 build process, which was abandoned in favor of cmake for Allegro 4.4 and also when DOS support was dropped. But you probably know that, so...

EDIT
From this : https://www.allegro.cc/forums/thread/599393/797084#target it seems it might have something to do with the C standard being used by your compiler. Try -std=c89 and see if that fixes it.

megatron-uk

Thanks for the tips, however, unless I'm completely mistaken when building the DOS target for liballegro the only option is a static library (unless I've missed something); DOS doesn't have a dynamic loader like Unix or Windows, so a .a file is the only thing you can create that makes any sense. Certainly the .a file I've got is a plain old ar archive, not a shared library.

In terms of link options for my code, it's a pure DOS allegro library and my cross compiler (i586-pc-msdosdjgpp) targets pure DOS as well (via either 5.5.0 or 7.2.0 djgpp version of GCC), it's not wingw32 or anything like that, so there's no linking with Windows dll's, for now that's just libc.a and liballeg.a:

#SelectExpand
1/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/lib $ ls -l 2total 7564 3-rw-r--r-- 1 megatron users 4516 Oct 18 2015 crt0.o 4-rw-r--r-- 1 megatron users 2720 May 11 2015 djgpp.djl 5-rw-r--r-- 1 megatron users 628 Aug 23 2017 dxe.ld 6-rw-r--r-- 1 megatron users 4558 Oct 18 2015 gcrt0.o 7drwxr-xr-x 2 megatron users 4096 Aug 23 2017 ldscripts 8-rw-r--r-- 1 megatron users 3230830 Sep 7 2007 liballd.a 9-rw-r--r-- 1 megatron users 1530832 Sep 7 2007 liballeg.a 10-rw-r--r-- 1 megatron users 1588764 Sep 7 2007 liballp.a 11-rw-r--r-- 1 megatron users 999320 Oct 18 2015 libc.a 12-rw-r--r-- 1 megatron users 45298 Oct 18 2015 libdbg.a 13-rw-r--r-- 1 megatron users 58804 Oct 18 2015 libemu.a 14-rw-r--r-- 1 megatron users 482 Oct 18 2015 libg.a 15-rw-r--r-- 1 megatron users 245346 Oct 18 2015 libm.a 16-rw-r--r-- 1 megatron users 482 Oct 18 2015 libpc.a

#SelectExpand
1megatron@thinky:/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/lib $ file liballeg.a 2liballeg.a: current ar archive 3 4megatron@thinky:/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/lib $ ar t liballeg.a | head -n 10 5allegro.o 6blit.o 7bmp.o 8clip3d.o 9clip3df.o 10colblend.o 11color.o 12config.o 13datafile.o 14dataregi.o 15... 16...

I must be missing something obvious here - I'm going to go right back to the version of GCC that Allegro was bundled with back in the days of DOS; I think it hung around v2.95 number for a very long time. Maybe something has broken with the modern binutils stuff?

---

Edit: Your link to that old post was a good one - although changing the C dialect looked at first to be disastrous (adding -std=c89 basically caused everything else to error out - I have examples of the later dynamic malloc calls, c++ style commenting, etc. etc.), it helped greatly in tracking down the actual cause; the inline functions in the headers.

One of the original commenters mentioned about a change in extern inline handling in c99, and sure enough, it's detailed here:

https://gcc.gnu.org/onlinedocs/gcc/Inline.html

The short version is that if compiling against Allegro 4.x on something more modern than GCC 2.x (which, if you're doing any DOS work these days, you'd be nuts for using so old a version of GCC), you need to pass the option -fgnu89-inline.

Otherwise, it will never work due to the inline functions in the headers.

I don't know how well this plays with other libraries, so your mileage may vary in that regard.

Here's the output:

...
/usr/i586-pc-msdosdjgpp/bin/i586-pc-msdosdjgpp-gcc -Wall -Wno-unused-function -Wno-unused-variable -march=i386 -mtune=i386 -mfpmath=387 -fgnu89-inline -O3 -I/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/sys-include  -DDOS -DALLEGRO_STATICLINK -DUSE_ALLEGRO -DDIR_SEP=\"\" -DGAMEDIR=\"C:\GAMES\" -DCSV_FILE=\"MENU.CSV\" -DALLEGRO_NO_COMPATIBILITY -DSTATICLINK=1 -DUSE_LOGGING -DLOGGING   -c -o src/gamedata.o src/gamedata.c
...

Linking....
/usr/i586-pc-msdosdjgpp/bin/i586-pc-msdosdjgpp-gcc -Wall -Wno-unused-function -DUSE_LOGGING -DLOGGING -g -o bin/menu_dos.exe src/menu.o src/logging.o src/input.o src/image.o src/qdbmp.o src/gfx.o src/bmp2text.o src/csvlib.o src/gamedata.o -L/usr/i586-pc-msdosdjgpp/i586-pc-msdosdjgpp/lib -lalleg

$ ls -l bin/menu_dos.exe
-rwxr-xr-x 1 megatron users 433952 Feb 18 20:13 menu_dos.exe

$ file bin/menu_dos.exe 
bin/menu_dos.exe: MS-DOS executable, COFF for MS-DOS, DJGPP go32 DOS extender

Edgar Reynaldo

I'm sorry, that was really more mingw advice, which I guess doesn't apply to DOS. I never really actually compiled anything for DOS, except for my very first programs with allegro. Glad you figured it out though. ;)

Thread #617748. Printed from Allegro.cc