[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