ld fails when building a 32bit c application

I’m trying to build the source for the Thompson-Davis Editor (http://adoxa.altervista.org/tde/), an old 32bit c application. The code compiles, but ld chokes with this message for each object file:


ld: i386 architecture of input file `<name>.o' is incompatible with i386:x86-64 output

I have added **CCFLAGS += -m32 ** and LDFLAGS += -m32 to the makefile, but the problem persists. (the tde makefile predates automake and its ilk.)
I have the following gcc packages installed:


@15:59:59,root@pinto
~
$ zypper se -i glibc
Loading repository data...
Reading installed packages...

S  | Name                     | Summary                                               | Type
---+--------------------------+-------------------------------------------------------+--------
i+ | glibc                    | Standard Shared Libraries (from the GNU C Library)    | package
i+ | glibc-32bit              | Standard Shared Libraries (from the GNU C Library)    | package
i+ | glibc-debuginfo          | Debug information for package glibc                   | package
i+ | glibc-debugsource        | Debug sources for package glibc                       | package
i+ | glibc-devel              | Include Files and Libraries Mandatory for Development | package
i+ | glibc-devel-32bit        | Include Files and Libraries Mandatory for Development | package
i+ | glibc-devel-debuginfo    | Debug information for package glibc-devel             | package
i+ | glibc-devel-static-32bit | C library static libraries for -static linking        | package
i+ | glibc-extra              | Extra binaries from GNU C Library                     | package
i+ | glibc-extra-debuginfo    | Debug information for package glibc-extra             | package
i  | glibc-i18ndata           | Database Sources for 'locale'                         | package
i+ | glibc-info               | Info Files for the GNU C Library                      | package
i+ | glibc-locale             | Locale Data for Localized Programs                    | package
i+ | glibc-locale-32bit       | Locale Data for Localized Programs                    | package
i+ | glibc-locale-debuginfo   | Debug information for package glibc-locale            | package
i+ | linux-glibc-devel        | Linux headers for userspace development               | package
@16:00:32,root@pinto
~
$ zypper se -i gcc
Loading repository data...
Reading installed packages...

S  | Name                      | Summary                                       | Type
---+---------------------------+-----------------------------------------------+--------
i+ | gcc                       | The system GNU C Compiler                     | package
i+ | gcc-32bit                 | The system GNU C Compiler                     | package
i+ | gcc-c++                   | The system GNU C++ Compiler                   | package
i+ | gcc-fortran               | The system GNU Fortran Compiler               | package
i  | gcc-gij                   | The system GNU Java bytecode interpreter      | package
i+ | gcc-info                  | The system GNU Compiler documentation         | package
i  | gcc-java                  | The system GNU Java Compiler                  | package
i+ | gcc48                     | The GNU C Compiler and Support Files          | package
i  | gcc48-32bit               | The GNU C Compiler 32bit support              | package
i+ | gcc48-c++                 | The GNU C++ Compiler                          | package
i+ | gcc48-c++-debuginfo       | Debug information for package gcc48-c++       | package
i+ | gcc48-debuginfo           | Debug information for package gcc48           | package
i+ | gcc48-debugsource         | Debug sources for package gcc48               | package
i+ | gcc48-fortran             | The GNU Fortran Compiler and Support Files    | package
i+ | gcc48-fortran-debuginfo   | Debug information for package gcc48-fortran   | package
i  | gcc48-gij                 | Java Bytecode Interpreter for gcc             | package
i+ | gcc48-info                | Documentation for the GNU compiler collection | package
i  | gcc48-java                | The GNU Java Compiler                         | package
i+ | libgcc_s1                 | C compiler runtime library                    | package
i+ | libgcc_s1-32bit           | C compiler runtime library                    | package
i+ | libgcc_s1-32bit-debuginfo | Debug information for package libgcc_s1-32bit | package
i+ | libgcc_s1-debuginfo       | Debug information for package libgcc_s1       | package

What more do I need to do to make ld happy?

I forgot to say also that the make file contains LDFLAGS += -L/usr/lib/

If you use ld directly (instead of using gcc as driver) you need to set correct target format with “-m elf_i386”.

Hmmm… this tarball is quite old, and has a pretty ancient makefile. I’m just starting to learn this stuff, so I’m not sure how to tell if the makefile is telling gcc to invoke ld or is invoking it itself. I’ll attach the makefile for clarity.


$ cat makefile
#
# Makefile for tde 5.1 for djgpp, unix & MinGW
# June 5, 1994, Frank Davis
# July 24, 1997, Jason Hood
# May 25, 1998, Jason Hood - combined unix and djgpp makefiles; added install
# August 23, 2002, Jason Hood - place object files in the OS directory
# August 27, 2002, Jason Hood - add win32 OS for MinGW32.
# March 18, 2003, Jason Hood - add BRIEF option.
#
# UNIX works with ncurses 1.8.5 (according to Frank).
#
# I've used make 3.79.1; it may work with previous versions.
#
# jmh 050818: changed djgpp project to "tdep.exe" (protected mode)
#             changed Win32 project to "tdew.exe" (Windows)
# jmh 050920: djgpp/Windows install as "tde.exe";
#             only create link for unix, at install; use supplied link file for
#              djgpp and Windows.
#

# Define the system for which to compile.
#OS = djgpp
#OS = win32
OS = unix

# Location to place the executable/binary file.
ifeq ($(OS),djgpp)
bindir = d:/utils
else
ifeq ($(OS),win32)
bindir = c:/utils
else
bindir = /usr/local/bin
endif
endif

# Should the executable/binary be stripped?
STRIP = strip
#STRIP = true

# Should the executable be compressed?
DJP = upx -9 -qq        # djgpp users should use v1.23.
#DJP = true

# Comment the following to see the compilation commands.
BRIEF = @

# Version number for the distribution
ifeq ($(VER),)
ifeq ($(OS),unix)
VER = 5.1
else
VER = 51
endif
endif

# CC="gcc -m32"
# LD="gcc -m32"
# AS="gcc -m32"

#CFLAGS = -Wall -g
CFLAGS  = -Wall -g
CFLAGS += -m32
CFLAGS += -O2 -finline-functions
CFLAGS += -mtune=pentiumpro -fomit-frame-pointer
CFLAGS += -DNDEBUG

LDFLAGS  = -s
LDFLAGS += -m32
LDFLAGS += -L/usr/lib/
LDFLAGS += --libdir=/usr/lib
LDFLAGS += --x-libraries=/usr/lib

ifeq ($(OS),unix)
CFLAGS += -D__UNIX__
# Uncomment the below to use the DOS graphics characters (codepage 437).
# Note: It doesn't work in an xterm.
#CFLAGS += -DPC_CHARS
PROJ    = tde
DBG     = tdedbg
LIBS    = -lncurses
else
ifeq ($(OS),win32)
PROJ    = tdew.exe
DBG     = tdewdbg.exe
LINK    = tdv.cmd               # XP batch to call tde -v
else
PROJ    = tdep.exe
DBG     = tdepdbg.exe
LINK    = tdv.exe               # links to tde *not* to tdep
endif
LIBS    =
endif

# CC = gcc

VPATH    = $(OS)
CPPFLAGS = -I.

OBJS = bj_ctype.o  block.o    cfgfile.o  config.o    console.o  criterr.o  \
       default.o   dialogs.o  diff.o     dirlist.o   ed.o       file.o     \
       filmatch.o  findrep.o  global.o   help.o      hwind.o    macro.o    \
       main.o      memory.o   menu.o     movement.o  port.o     prompts.o  \
       pull.o      query.o    regx.o     sort.o      syntax.o   tab.o      \
       undo.o      utils.o    window.o   wordwrap.o

OBJECTS = $(addprefix $(OS)/, $(OBJS))

INC  = tdestr.h common.h tdefunc.h define.h

$(OS)/%.o : %.c
ifdef BRIEF
        @echo Compiling $<
endif
        $(BRIEF)$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

$(PROJ): $(OBJECTS)
ifdef BRIEF
        @echo Creating $(PROJ)
endif
        $(BRIEF)$(CC) -o $@ $^ $(LIBS)

$(OS)/bj_ctype.o:  bj_ctype.c bj_ctype.h tdestr.h common.h
$(OS)/block.o:     block.c    $(INC)
$(OS)/cfgfile.o:   cfgfile.c  tdestr.h syntax.h config.h
$(OS)/config.o:    config.c   config.h $(INC)
$(OS)/console.o:   console.c  $(INC)
$(OS)/criterr.o:   criterr.c  criterr.h $(INC)
$(OS)/default.o:   default.c  tdestr.h define.h
$(OS)/dialogs.o:   dialogs.c  tdestr.h
$(OS)/diff.o:      diff.c     $(INC)
$(OS)/dirlist.o:   dirlist.c  $(INC)
$(OS)/ed.o:        ed.c       $(INC)
$(OS)/file.o:      file.c     $(INC)
$(OS)/filmatch.o:  filmatch.c filmatch.h tdestr.h common.h
$(OS)/findrep.o:   findrep.c  $(INC)
$(OS)/global.o:    global.c   tdestr.h tdefunc.h
$(OS)/help.o:      help.c
$(OS)/hwind.o:     hwind.c    $(INC)
$(OS)/macro.o:     macro.c    $(INC)
$(OS)/main.o:      main.c     $(INC)
$(OS)/memory.o:    memory.c   $(INC)
$(OS)/menu.o:      menu.c     tdestr.h define.h
$(OS)/movement.o:  movement.c $(INC)
$(OS)/port.o:      port.c     $(INC)
$(OS)/prompts.o:   prompts.c  bj_ctype.h
$(OS)/pull.o:      pull.c     $(INC)
$(OS)/query.o:     query.c    $(INC)
$(OS)/regx.o:      regx.c     $(INC)
$(OS)/sort.o:      sort.c     $(INC)
$(OS)/syntax.o:    syntax.c   syntax.h $(INC)
$(OS)/tab.o:       tab.c      $(INC)
$(OS)/undo.o:      undo.c     $(INC)
$(OS)/utils.o:     utils.c    $(INC)
$(OS)/window.o:    window.c   $(INC)
$(OS)/wordwrap.o:  wordwrap.c $(INC)

install: $(PROJ)
        cp $(PROJ) $(DBG)
        -$(STRIP) $(PROJ)
        -$(DJP) $(PROJ)
ifeq ($(OS),unix)
        cp $(PROJ) $(bindir)
        ln -fs $(bindir)/$(PROJ) $(bindir)/tdv
else
        cp $(PROJ) $(bindir)/tde.exe
        cp $(LINK) $(bindir)
endif

clean:
        rm -f $(OS)/*.o

dist:
ifeq ($(OS),unix)
        tar -cf tde-$(VER).tar.gz --name-prefix=tde-$(VER)/ \
        --files-from=src.lst --gzip
else
        mv tde.shl tdesrc.shl
        mv tdedist.shl tde.shl
        zip -X9 tde$(VER)b -@ <bin.lst
        mv tde.shl tdedist.shl
        mv tdesrc.shl tde.shl
        zip -X9 tde$(VER)s -@ <src.lst
endif

Uncomment

# LD="gcc -m32"

?

Tried that, but it produces


$ make
Compiling bj_ctype.c
/bin/sh: gcc -m32: command not found
makefile:113: recipe for target 'unix/bj_ctype.o' failed
make: *** [unix/bj_ctype.o] Error 127

So I tried this combination


LD=gcc
LDFLAGS  = -s
LDFLAGS += -m32

and now I get the same original failure.

Here is the original, unmodified makefile as it exists in the tarball.


$ cat makefile
#
# Makefile for tde 5.1 for djgpp, unix & MinGW
# June 5, 1994, Frank Davis
# July 24, 1997, Jason Hood
# May 25, 1998, Jason Hood - combined unix and djgpp makefiles; added install
# August 23, 2002, Jason Hood - place object files in the OS directory
# August 27, 2002, Jason Hood - add win32 OS for MinGW32.
# March 18, 2003, Jason Hood - add BRIEF option.
#
# UNIX works with ncurses 1.8.5 (according to Frank).
#
# I've used make 3.79.1; it may work with previous versions.
#
# jmh 050818: changed djgpp project to "tdep.exe" (protected mode)
#             changed Win32 project to "tdew.exe" (Windows)
# jmh 050920: djgpp/Windows install as "tde.exe";
#             only create link for unix, at install; use supplied link file for
#              djgpp and Windows.
#

# Define the system for which to compile.
#OS = djgpp
#OS = win32
OS = unix

# Location to place the executable/binary file.
ifeq ($(OS),djgpp)
bindir = d:/utils
else
ifeq ($(OS),win32)
bindir = c:/utils
else
bindir = /usr/local/bin
endif
endif

# Should the executable/binary be stripped?
STRIP = strip
#STRIP = true

# Should the executable be compressed?
DJP = upx -9 -qq        # djgpp users should use v1.23.
#DJP = true

# Comment the following to see the compilation commands.
BRIEF = @

# Version number for the distribution
ifeq ($(VER),)
ifeq ($(OS),unix)
VER = 5.1
else
VER = 51
endif
endif

CFLAGS  = -Wall -g
CFLAGS += -O2 -finline-functions
CFLAGS += -mtune=pentiumpro -fomit-frame-pointer
CFLAGS += -DNDEBUG

ifeq ($(OS),unix)
CFLAGS += -D__UNIX__
# Uncomment the below to use the DOS graphics characters (codepage 437).
# Note: It doesn't work in an xterm.
#CFLAGS += -DPC_CHARS
PROJ    = tde
DBG     = tdedbg
LIBS    = -lncurses
else
ifeq ($(OS),win32)
PROJ    = tdew.exe
DBG     = tdewdbg.exe
LINK    = tdv.cmd               # XP batch to call tde -v
else
PROJ    = tdep.exe
DBG     = tdepdbg.exe
LINK    = tdv.exe               # links to tde *not* to tdep
endif
LIBS    =
endif

CC = gcc

VPATH    = $(OS)
CPPFLAGS = -I.

OBJS = bj_ctype.o  block.o    cfgfile.o  config.o    console.o  criterr.o  \
       default.o   dialogs.o  diff.o     dirlist.o   ed.o       file.o     \
       filmatch.o  findrep.o  global.o   help.o      hwind.o    macro.o    \
       main.o      memory.o   menu.o     movement.o  port.o     prompts.o  \
       pull.o      query.o    regx.o     sort.o      syntax.o   tab.o      \
       undo.o      utils.o    window.o   wordwrap.o

OBJECTS = $(addprefix $(OS)/, $(OBJS))

INC  = tdestr.h common.h tdefunc.h define.h

$(OS)/%.o : %.c
ifdef BRIEF
        @echo Compiling $<
endif
        $(BRIEF)$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

$(PROJ): $(OBJECTS)
ifdef BRIEF
        @echo Creating $(PROJ)
endif
        $(BRIEF)$(CC) -o $@ $^ $(LIBS)

$(OS)/bj_ctype.o:  bj_ctype.c bj_ctype.h tdestr.h common.h
$(OS)/block.o:     block.c    $(INC)
$(OS)/cfgfile.o:   cfgfile.c  tdestr.h syntax.h config.h
$(OS)/config.o:    config.c   config.h $(INC)
$(OS)/console.o:   console.c  $(INC)
$(OS)/criterr.o:   criterr.c  criterr.h $(INC)
$(OS)/default.o:   default.c  tdestr.h define.h
$(OS)/dialogs.o:   dialogs.c  tdestr.h
$(OS)/diff.o:      diff.c     $(INC)
$(OS)/dirlist.o:   dirlist.c  $(INC)
$(OS)/ed.o:        ed.c       $(INC)
$(OS)/file.o:      file.c     $(INC)
$(OS)/filmatch.o:  filmatch.c filmatch.h tdestr.h common.h
$(OS)/findrep.o:   findrep.c  $(INC)
$(OS)/global.o:    global.c   tdestr.h tdefunc.h
$(OS)/help.o:      help.c
$(OS)/hwind.o:     hwind.c    $(INC)
$(OS)/macro.o:     macro.c    $(INC)
$(OS)/main.o:      main.c     $(INC)
$(OS)/memory.o:    memory.c   $(INC)
$(OS)/menu.o:      menu.c     tdestr.h define.h
$(OS)/movement.o:  movement.c $(INC)
$(OS)/port.o:      port.c     $(INC)
$(OS)/prompts.o:   prompts.c  bj_ctype.h
$(OS)/pull.o:      pull.c     $(INC)
$(OS)/query.o:     query.c    $(INC)
$(OS)/regx.o:      regx.c     $(INC)
$(OS)/sort.o:      sort.c     $(INC)
$(OS)/syntax.o:    syntax.c   syntax.h $(INC)
$(OS)/tab.o:       tab.c      $(INC)
$(OS)/undo.o:      undo.c     $(INC)
$(OS)/utils.o:     utils.c    $(INC)
$(OS)/window.o:    window.c   $(INC)
$(OS)/wordwrap.o:  wordwrap.c $(INC)

install: $(PROJ)
        cp $(PROJ) $(DBG)
        -$(STRIP) $(PROJ)
        -$(DJP) $(PROJ)
ifeq ($(OS),unix)
        cp $(PROJ) $(bindir)
        ln -fs $(bindir)/$(PROJ) $(bindir)/tdv
else
        cp $(PROJ) $(bindir)/tde.exe
        cp $(LINK) $(bindir)
endif

clean:
        rm -f $(OS)/*.o

dist:
ifeq ($(OS),unix)
        tar -cf tde-$(VER).tar.gz --name-prefix=tde-$(VER)/ \
        --files-from=src.lst --gzip
else
        mv tde.shl tdesrc.shl
        mv tdedist.shl tde.shl
        zip -X9 tde$(VER)b -@ <bin.lst
        mv tde.shl tdedist.shl
        mv tdesrc.shl tde.shl
        zip -X9 tde$(VER)s -@ <src.lst
endif

I have tried inserting LD = gcc (once above the various *FLAGS statements, and once down with the CC = gcc statement) together with LDFLAGS = -m32 and alternatively LD = “gcc -m32”, and also LDFLAGS += -L/usr/lib and LDFLAGS += --libdir=/usr/lib. None of these has helped, and LD = “gcc -m32” won’t even run the compile phase. Apparently something else is needed?

This makefile hardcodes linking command, just add -m32 flag there.

So, insert -m32 before -o ? If, instead, I wanted to use LDFLAGS, as the compile recipe does, how would that look?

Inserting -m32 before -o fixes most of the linking errors, but for these:


/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /lib64/libncurses.so.5 when searching for /lib64/libncurses.so.5
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find /lib64/libncurses.so.5
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib64/gcc/x86_64-suse-linux/4.8/../../../libtinfo.so when searching for -ltinfo
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib64/gcc/x86_64-suse-linux/4.8/../../../libtinfo.a when searching for -ltinfo
/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -ltinfo
collect2: error: ld returned 1 exit status
makefile:113: recipe for target 'tde' failed
make: *** [tde] Error 1
@19:28:06,leslie@pinto

This makes me think that I need also at least -L/usr/lib as well. I’ll have to look into the state of libncurses and libtinfo.

Well, for some reason, libncurses and libtinfo are in /lib, not /usr/lib, but inserting -L/lib into various positions in $(BRIEF)$(CC) -m32 -o $@ $^ $(LIBS) does nothing helpful, so now I’m stymied again. -L doesn’t seem to be doing what I expect from reading the ld man file. I’m not sure exactly what LIBS = -lncurses does, or how it could imply that /lib64 should be searched. I tried putting -L/lib before -o, before $(LIBS) and after $(LIBS), but to no effect; make still is searching /lib64.

You need 32bit development packages to build 32bit applications. Assuming you are on openSUSE, this would be ncurses-devel-32bit etc.

Gaah! I was sure that I had seen ncurses-devel-32bit in my list of installed packages, but no, it wasn’t. Now it is, and that was the key.

Thanks, arvijaar.