[mercury-users] Strange linking problem

Ondrej Bojar oboj7042 at ss1000.ms.mff.cuni.cz
Mon Jan 28 04:49:52 AEDT 2002


Hi.

  I link together a lot of mercury modules and some C++ modules. The whole
project is wrapped into a module called ent. Module ent defines the
main(io, io) predicate and it's only task is to call a cpp_main function
defined in one of the C++ modules. It works fine.

  But sometimes, when the big project gets compiled, the executable does
nothing. (It doesn't crash, but it doesn't call my main(io, io) in ent.m.)

  I figured out that touching ent.m is not sufficient (my Mmakefile seems
to be buggy and doesn't recompile ent.m into ent.c), also touching
ent_cpp_main.cc doesn't help (though ent_cpp_main.o is recompiled
correctly).

  What helps is running mmake ent.depend and then mmake ent.

  Where could the bug be? Why linker doesn't issue any errors?

Thanks, Andrew.

P.S.: I attach my Mmakefile, ent.m and ent_cpp_main.cc, but there's a lot
of unnecessary code in it.
-------------- next part --------------
### Main rules to build the final target: executable "ent"
MAIN_TARGET=ent
depend: ent.depend dbremake commremake


### Tune this option to get best performance.
# For now, we've got two processors
JOBS=-j4
#JOBS=

###### ENTIROOT
# Nyni se predpoklada, ze make je spusten v ENTIROOT/src/ent/lingv2
ENTIROOT=../../..

# Propojeni se zdrojaky Milana
db_dir=../milan
db_objects=$(db_dir)/db.o $(db_dir)/seznam.o $(db_dir)/veta.o $(db_dir)/reakce.o

.PHONY: dbremake
dbremake:
	cd $(db_dir); make

# Propojeni s komunikaci
comm_dir=$(ENTIROOT)/src/shared/comm/
comm_objects=$(comm_dir)/comm.o $(comm_dir)/report.o

.PHONY: commremake
commremake:
	cd $(comm_dir); make

# Where are the sources of main program stored:
main_subdir=.
main_objects=$(main_subdir)/komplex.o $(main_subdir)/ent_cpp_main.o

###### Parametry kompilace
GRADEFLAGS= --debug
CFLAGS=-I$(ENTIROOT)/src/shared/ -I$(main_subdir) -I$(comm_dir)


# Files needed for plain compilation of mercury-based stuff
# For other reasons, the mercury sources here do need some C stuff as well
#MLOBJS=db_cint.o $(db_objects)

# Files needed for the final linking.
#MLOBJS-ent=db_cint.o $(db_objects) $(main_objects)
# XXX Strangely, the line above *doesn't work*. When "mmake ent" is called,
# mmake *doesn't include* the $(main_objects) and includes just plain $(MLOBJS)
# I can fix this bug only by replacing both the MLOBJS lines with the next one
# just for the phase of linking:
MLOBJS=db_cint.o $(db_objects) $(main_objects) $(comm_objects)

# This is to tell that "main" function should not be prepared by Mercury, but is
# included from somewhere else (testent.o)
# C2INITFLAGS-ent= --library
# This is no longer true. main() function is defined in ent.m, Mercury does the
# main wrapping.

# Mercury Compiler by umel vypsat statistiky o narocnosti kompilace
#MCFLAGS=-S

# Lze pridat -v, aby bylo videt, jak se presne MGNUC pousti
MGNUCFLAGS=-I $(db_dir)

# doplnuji ve snaze presvedcit Mercury, aby pracoval s C++
C2INITFLAGS-lingv_mint=--library

###### Rules for compiling main() function defined in ent.cc:

# header file so that C++ can call predicates from Mercury
# to get the header file, just compile lingv_mint.m into lingv_mint.o,
# as a side-effect, there's the file.
lingv_mint.h: lingv_mint.o

# same applies to csts.h
csts.h: csts.o

komplex.cc: lingv_mint.h csts.h

### Dependences of ent_cpp_main:

ent: ent_cpp_main.o konf_fak.txt ent.m
# konf_fak.txt is an auxiliary file, contains database information

ent_cpp_main.o: docasna_komunikace.inc.cc ent_cpp_main.h


###### Pravidla, aby mmake umel kompilovat .cc na .o

%.o: %.cc
	$(CXX) $(CXXFLAGS) -c $*.cc

CXX=$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS)

###### Pravidla pro preprocessing zdroju .pproc, .shan a .ordie, aby vznikaly .m
HANDLES=$(ENTIROOT)/src/conf/handles
DOHANDLES=$(ENTIROOT)/src/tools/dohandles.pl
DHFLAGS=--handles=$(HANDLES)

%.m: %.m.shan $(DOHANDLES) $(HANDLES)
	$(DOHANDLES) $(DHFLAGS) --quiet $*.m.shan
	mmake $(JOBS) $*.depend

%.txt: %.txt.shan $(DOHANDLES) $(HANDLES)
	$(DOHANDLES) $(DHFLAGS) --quiet --decimal $*.txt.shan
%.cc: %.cc.shan $(DOHANDLES) $(HANDLES)
	$(DOHANDLES) $(DHFLAGS) --quiet --decimal $*.cc.shan

%.m: %.ordie ordie.pl
	./ordie.pl $<

PPROC=./pproc
# preprocesor jako od Ccka, ale tak, aby vystup sezral i Mercury
%.m: %.m.pproc $(PPROC)
	$(PPROC) $*.m.pproc
	mmake $(JOBS) $*.depend
%.vierrs: %.err vim_showerrors
	./maperrs.pl < $*.err > $*.vierrs
	vim -S vim_showerrors -c "cf $*.vierrs"


### Pomucka na ladeni

#testdb: konf_fak.txt

###### Makra pro programatora

.PHONY=sources
sources: filterprintoutfiles.pl
	mmake $(JOBS) `./files --suffix=m`
.PHONY=depends
depends: files filterprintoutfiles.pl
	mmake $(JOBS) `./files --suffix=depend`

.PHONY=objects
objects: files filterprintoutfiles.pl
	mmake $(JOBS) `./files --suffix=o`

.PHONY=superclean
superclean: realclean files filterprintoutfiles.pl
	rm -f `./files --deletable`
	rm -f `./files --suffix=vierrs`
	rm -f testent.o komplex.o

#all: *.o

#allerrs: *.o
#	for f in *.o; do mmake $$f; done
#	mmake merrs

#init.o: lingv_mint_init.o init.o_files
#	mv lingv_mint_init.o init.o
#init.o_files: lingv_mint_init.c
#	sed -n -e "s/\*\* \([^.]*\)\.c/\1.o/p" lingv_mint_init.c > init.o_files

#lingv_mint_init.o: lingv_mint_init.c

.PHONY: merrs
merrs: maperrs.pl
	cat *.err | ./maperrs.pl > merrs

#depend: sources
#	mmake `ls *.m | sed -e 's/\.m/.depend/g'`

#tests:
#	mmake `ls test*.m | sed -e 's/\.m//g'`

errors:
	rm -f errors.log
	find -maxdepth 1 -name "*.m" -exec makeerror {} \;
	grep -v "OK" errors.log > errors.log.tmp
	mv errors.log.tmp errors.log
	find . -size 0 -exec rm -f {} \;
newerrors:
	mmake -j4 `./files --suffix=o`
#fasterrors:
#	grep -v "OK" errors.log | cut -d: -f1 > tmp.fnames.fasterrors
#	rm -f errors.log
#	for fname in `cat tmp.fnames.fasterrors`; do makeerror $$fname; done
#	rm -f tmp.fnames.fasterrors
#
preds:
	grep "^:- pred\|^:- func" `ls *.m *.shan *.ordie *.pproc | sort | ./filterprintoutfiles.pl` | sed -e 's/::- /:/'

printout:
	ls *.m *.shan *.ordie *.pproc | sort | ./filterprintoutfiles.pl | grep -v "^test" > /tmp/files
	head -n 32000 `cat /tmp/files` | grep -v "^:- i" | grep -v ":- module" | cat -s >printout.txt

domu: homepack ziphomepack

SOUBORY_DOMU=konf_fak.txt.shan local_handles *.out rozhovory/*.entout rozhovory/*.err rozhovory/*.incstsforms.shan *.err *.txt *.morfout `ls *.m *.shan *.ordie *.pproc | ./filterprintoutfiles.pl`

local_handles:$(HANDLES)
	cp $(HANDLES) local_handles

homepack: local_handles
	rm -f printout.txt
	find . -size 0 -exec rm {} \;
	tar czf domu.tgz $(SOUBORY_DOMU)

ziphomepack: local_handles
	rm -f printout.txt
	find . -size 0 -exec rm {} \;
	rm -f domu.zip
	zip domu.zip $(SOUBORY_DOMU)

wc:
	wc `ls *.m *.shan *.ordie *.pproc | ./filterprintoutfiles.pl`

#remake: clean depend

#realremake: realclean depend

#runaway: realclean sources depend errors ziphomepack homepack

-------------- next part --------------
:- module ent.
:- import_module lingv_mint.

% Wrapper, main module of ent. In fact just calls cpp_main() defined in ent.cc

:- interface.

:- import_module io.

:- pred main(io::di, io::uo) is det.
 
:- implementation.

:- import_module string, list, int.
 
        % #include the header file containing the function prototype
        % for cpp_main(), using a `pragma c_header_code' declaration.
        % Note that any double quotes or backslashes in the C code for
        % the `#include' line must be escaped, since the C code is
        % given as a Mercury string.
:- pragma c_header_code("#include \"ent_cpp_main.h\"").
 
        % Define the Mercury predicate cpp_main to call the C++ function
        % cpp_main.
:- pred cpp_main(string::in, int::in, int::out, io__state::di, io__state::uo) is det.
:- pragma c_code(cpp_main(Host::in, Port::in, RetVal::out, IO0::di, IO::uo), may_call_mercury, "
        RetVal = cpp_main(Host, Port);
        IO = IO0;
").

% main just invokes cpp_main
main -->
        io__stderr_stream(StdErr),
        io__write_string(StdErr, "In Mercury main, about to call cpp_main...\n"),
        io__command_line_arguments(Args),
        {
          if Args=[THost, TPortStr], string__to_int(TPortStr, TPort)
          then 
            Host = THost, Port = TPort
          else
            Host = "", Port = 0
        },
        cpp_main(Host, Port, RetVal),
        io__write_string(StdErr, "Back in Mercury main. cpp_main returned "),
        io__write_int(StdErr, RetVal),
        io__write_string(StdErr, ".\n").

-------------- next part --------------
/* Testovaci ent jako takovy:
 *   - pripojen na databazi
 *   - pripojen na lingvistiku
 */

/** Link to our own header file **/
#include "ent_cpp_main.h"

/** Pripojeni na databazi **/
#include "db.h"

/** Pripojeni na Mercury a na lingvistiku **/
#include "komplex.h"
  /* komplex je komplex vseho, co je potreba pro praci s lingv. a mercury */

#include "string.h"
/* ladeni, vstup zadratovanych vet. */

/* globalni promenne */
THandl Ja; ///muj handl
THandl AktCas; ///handl aktualniho casu
THandl AktMistnost; ///handl mistnosti, ve ktere se nachazim (i konkretni dlazdice)

#include <unistd.h>
  /*sleep*/
#include "docasna_komunikace.inc.cc"
  /* obsahuje vsechny rutiny i globalni promenne pouzivane v komunikaci se SP */

int cpp_main(char * host, int port) {
    /* parametry host a port nam predava Mercury, jde o prvni dva parametry
     * z prikazove radky
     * Testovaci prubeh tohoto enta se v pripade dodani parametru snazi pripojit
     * k serveru prostredi
     */
    int dbstate;
    TLinMem LinMem, NewLinMem;

    fprintf(stderr, "cpp_main: spusten.\n");

    db_inicializace(); ///zakladni inicializade DB

    ///inicializace povolenych handlu
    if(!db_inicializace_povolenehandly("./konf_povol.txt"))
      fprintf(stderr, "cpp_main: Chyba pri nacitani povolenych handlu!\n"); 

    dbstate = db_inicializace_fakta("./konf_fak.txt");
    fprintf(stderr, "cpp_main: inicializovana databaze, navratova hodnota %i.\n", dbstate);
    LinMem = komplexne_inicializuj(dbstate);
    fprintf(stderr, "cpp_main: inicializovana lingvisticka pamet, navratova hodnota %i.\n", LinMem);

    /* Zde je zakladni vetveni testovaciho ent_cpp_main.cc
     * Bud je zadan 'host' a 'port', pak se pripojuji k SP a posilam mu noop
     * Nebo je host==0 a port ==0 a pak beru ze STDIN zadratovane vety.
     */

    if (host && port) {

        fprintf(stderr, "ent_cpp_main: Spusten ve variante, kdy se zkousim napojit na server prostredi.\n");
        fprintf(stderr, "ent_cpp_main: hledam server prostredi, host=%s port=%i\n", host, port);

        report = new CReport();
        server_desc = connect_to_server(host, port);

        if (server_desc == -1) {
            fprintf(stderr, "ent_cpp_main: nedokazal pripojit k serveru prostredi.\n");
            return 1;
        }

        read_from_server(); /* nactu inicializaci od SP */

        fprintf(stderr, "ent_cpp_main: Nacetl jsem inicializaci od serveru. Ja jsem ent cislo: %i\n", Ja);

        /* prazdna smycka */
        fprintf(stderr, "ent_cpp_main: ted budu porad posilat NOOP, co deset vterin.\n");

        while (1) {
            sleep(10);
            send_nop();
            read_from_server();  /* nactu a vytisknu vysledek noopu */
            fprintf(stderr, "cpp_main: stiskni ctrl-C, jestli to chces skoncit\n");
        }

    }
    /* sem, za if se dostaneme, jen pokud host==0 nebo port == 0 */
    
    char *input;
    char *output;

    fprintf(stderr, "cpp_main: Postupne lingvistice predam cvicne vstupni vety.\n");
    fprintf(stderr, "cpp_main: Nyni ocekavam, ze mi je na vstup das v hezkem formatu.\n");
    fprintf(stderr, "cpp_main: Jestli ten format neznas, zmackni ted ctrl-D a spust mne znovu, stdin mi ovsem prismeruj ze souboru lingv2/cvicne_vstupy/rozhovor1.morfout\n");

    char bigbuf[10000]="";
    char buf[10000]="";
    char *line;
    input = bigbuf;
    while (line = gets(buf)) {
      /* never use gets, debugging only! */
      if (*line) {
          /* neprazdna radka -- pripravuj vstup pro lingv */
          strcat(line, "\n");
          strcat(input, line);
      } else {
        fprintf(stderr, "cpp_main: Zpracovavam vstup:\n%s--------\n\n", input);

        output = komplexne_zpracuj(LinMem, &NewLinMem, input);
        /* komplexne_zpracuj celou vetu poslechne, neuspele-li vrati chybovou
         * hlasku (v podobe urcene k odeslani ven),
         * uspeje-li, zavola smyslove reakce a vrati zpracovanou reakci.
         *
         * Ve zvlastnim pripade muze vratit pointer na "", prazdny retezec.
         * To znamena, ze se nema nic posilat ven, proste se ma veta tise
         * spolknout.
         * 
         * !!! Pozor, volajici je nadale zodpovedny za dealokovani outputu !!!
         */
    
        fprintf(stderr, "cpp_main: Takto probehla reakce:\n");
        fprintf(stderr, "IN:\n%s\nOUT:\n%s\n\n", input, output);
        printf("%s\n", output);

        /* dealokujme output */
        fprintf(stderr, "cpp_main: dealokuji stary output.\n");
        free(output);

        /* pro pristi kolo ma byt LinMem jako se ted vratila */
        fprintf(stderr, "cpp_main: OldLinMem: %i, NewLinMem: %i\n", LinMem, NewLinMem);
        LinMem = NewLinMem;
        fprintf(stderr, "cpp_main: Presunul pameti; OldLinMem: %i, NewLinMem: %i\n", LinMem, NewLinMem);

        fprintf(stderr, "cpp_main: Zapominam minuly vstup, pripravuji se na novy.\n");
        input = bigbuf;
        *input = 0;
      }

    }

    fprintf(stderr, "cpp_main: koncim, vracim 0.\n");
    return 0;
}


More information about the users mailing list