How to use and build a makefile to link scip to C? - c

I am very new in C. I just need to use one of the functions in scip. I made a make file as below:
SCIPDIR=$/Users/amin/Documents/cProgram/scipoptsuite-6.0.2/scip
include $(SCIPDIR)/make/make.project
%.o: %.c
$(CC) $(FLAGS) $(OFLAGS) $(BINOFLAGS) $(CFLAGS) -c $<
all: cmain
cmain: cmain.o
$(LINKCXX) cmain.o $(LINKCXXSCIPALL) $(LDFLAGS) $(LINKCXX_o) cmain
my cmain.c file is like this:
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* This file is part of the program and library */
/* SCIP --- Solving Constraint Integer Programs */
/* */
/* Copyright (C) 2002-2019 Konrad-Zuse-Zentrum */
/* fuer Informationstechnik Berlin */
/* */
/* SCIP is distributed under the terms of the ZIB Academic License. */
/* */
/* You should have received a copy of the ZIB Academic License */
/* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**#file GMI/src/cmain.c
* #brief main file for GMI cut example
* #author Marc Pfetsch
*/
/*--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
#include <scip/scip.h>
#include <scip/scipdefplugins.h>
/** reads parameters */
static
SCIP_RETCODE readParams(
SCIP* scip, /**< SCIP data structure */
const char* filename /**< parameter file name, or NULL */
)
{
if ( filename != NULL )
{
if ( SCIPfileExists(filename) )
{
SCIPinfoMessage(scip, NULL, "reading parameter file <%s> ...\n", filename);
SCIP_CALL( SCIPreadParams(scip, filename) );
}
else
SCIPinfoMessage(scip, NULL, "parameter file <%s> not found - using default parameters.\n", filename);
}
else if ( SCIPfileExists("scipgmi.set") )
{
SCIPinfoMessage(scip, NULL, "reading parameter file <scipgmi.set> ...\n");
SCIP_CALL( SCIPreadParams(scip, "scipgmi.set") );
}
return SCIP_OKAY;
}
/** starts SCIP */
static
SCIP_RETCODE fromCommandLine(
SCIP* scip, /**< SCIP data structure */
const char* filename /**< input file name */
)
{
/********************
* Problem Creation *
********************/
SCIPinfoMessage(scip, NULL, "read problem <%s> ...\n\n", filename);
SCIP_CALL( SCIPreadProb(scip, filename, NULL) );
/*******************
* Problem Solving *
*******************/
/* solve problem */
SCIPinfoMessage(scip, NULL, "solve problem ...\n\n");
SCIP_CALL( SCIPsolve(scip) );
SCIPinfoMessage(scip, NULL, "primal solution:\n");
SCIP_CALL( SCIPprintBestSol(scip, NULL, FALSE) );
/**************
* Statistics *
**************/
SCIPinfoMessage(scip, NULL, "Statistics:\n");
SCIP_CALL( SCIPprintStatistics(scip, NULL) );
return SCIP_OKAY;
}
/** starts user interactive mode */
static
SCIP_RETCODE interactive(
SCIP* scip /**< SCIP data structure */
)
{
SCIP_CALL( SCIPstartInteraction(scip) );
return SCIP_OKAY;
}
/** creates a SCIP instance with default plugins, evaluates command line parameters, runs SCIP appropriately,
* and frees the SCIP instance
*/
static
SCIP_RETCODE runSCIP(
int argc, /**< number of shell parameters */
char** argv /**< array with shell parameters */
)
{
SCIP* scip = NULL;
/*********
* Setup *
*********/
/* initialize SCIP */
SCIP_CALL( SCIPcreate(&scip) );
/* we explicitly enable the use of a debug solution for this main SCIP instance */
SCIPenableDebugSol(scip);
/***********************
* Version information *
***********************/
SCIPprintVersion(scip, NULL);
SCIPinfoMessage(scip, NULL, "\n");
/* include default SCIP plugins */
SCIP_CALL( SCIPincludeDefaultPlugins(scip) );
/**************
* Parameters *
**************/
if ( argc >= 3 )
{
SCIP_CALL( readParams(scip, argv[2]) );
}
else
{
SCIP_CALL( readParams(scip, NULL) );
}
/**************
* Start SCIP *
**************/
if ( argc >= 2 )
{
SCIP_CALL( fromCommandLine(scip, argv[1]) );
}
else
{
SCIPinfoMessage(scip, NULL, "\n");
SCIP_CALL( interactive(scip) );
}
/********************
* Deinitialization *
********************/
SCIP_CALL( SCIPfree(&scip) );
BMScheckEmptyMemory();
return SCIP_OKAY;
}
/** main method starting SCIP */
int main(
int argc, /**< number of arguments from the shell */
char** argv /**< array of shell arguments */
)
{
SCIP_RETCODE retcode;
retcode = runSCIP(argc, argv);
if ( retcode != SCIP_OKAY )
{
SCIPprintError(retcode);
return -1;
}
return 0;
}
Now in the directory that I have these 2 file, I run Make but it doesn't work I get error: No such file or directory
make: *** No rule to make target `Users/amin/Documents/cProgram/scipoptsuite-6.0.2/scip/make/make.project'. Stop.
I just tried to follow a instruction that someone suggested. Please help me if you can. what I have to do?

You are going about this incorrectly.
First without target the first recipe is the one called, so the all target should go first.
second: don't include that other file and delete just about everything but the directory variable and the all target
you simply need to add to the LD_FLAGS variable and the automatic rules will link for you. unless the scip project is bringing in a bunch of variables that you need I don't know why you would need to include its make file information here.
Also of note is that the current path you loaded into a variable had an incorrect leading $ sign in the assignment, and for this to link we will need to make sure its full path to libscip.so ( or libscip.a )
i.e. LD_FLAGS+=-L${DIR_containing_libscip.so} -lscip
you might also need to point to the header/include files:
CPP_FLAGS+=-I${DIR_before_includes_of_scip}/include ( if they are included as <scip/foo>. or without the /include and going up further if they are to be included just as <foo>; this depends upon the projects style. Most projects use the /include/projname pattern so as to keep the project effectively in a namespace of its own for include files to avoid collisions.
that should be it assuming everything else is built and in place and there is nothing particularly special about scip that I need to know about...

You want to separate two things
Building SCIP
Building and Linking your program.
Building SCIP
Usually one would go about and install this library using a package manager on most UNIX-like systems, or do make install to copy it into the system. Then, header files etc. will automatically be found. If you don't want to do that but rather "bundle" SCIP with your program, you usually distribute a copy or link a copy of that version for your program (copy of the code in your sourcetree under eg. "external" or using git submodules, ...). In any case though, you don't want the path to SCIP to be absolute. As an example, use this layout:
./
-- external/SCIP
-- cmain.c
-- Makefile
In the Makefile you can then set SCIPDIR like this for later use:
SCIPDIR := "./external/SCIP"
First, however, you should understand how to build manually. For that, you enter "./external/SCIP" and build the library as instructed in the Readme (often by doing something like ./configure && make && make install). If you want to automate this, you can do this from your main file. For that you can add a "phony" target (ie. a target that will not exactly create one output but build all dependencies) that we will call dep:
dep:
cd $(SCIPDIR); ./configure
$(MAKE) -C $(SCIPDIR)
.PHONY: dep
(thanks to #UpAndAdam for pointing out that you have to change the CWD before running the configure script)
For that we recursively call make for our subproject. We don't want to system-wide install the files, so we just build the library.
Building your program
We now add two pattern-rules that specify how to build and link C programs. GNU/Make (the one you're using) already has built-in suffix rules s.t. it already by default knows how to build C programs, but suffix rules are hard to deal with and you already use other GNU/Make features, so we can also use pattern-rules that are roughly equivalent and disable the built-in rules:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
%: %.o
$(CC) $(LDFLAGS) $(CFLAGS) -o $# $^ $(LDLIBS)
.SUFFIXES:
A small note here: We compile one object file from one c file by pattern matching. I used the standard variables, CPPFLAGS (C preprocessor, not C++!), CFLAGS (C compiler & Feature flags) and listed all options before the non-option argument $< which will hold the (first) dependency listed, eg. "cmain.c". Not all C compilers allow mixing options and arguments.
For linking I do the same, but I list the libraries that we want to link with last. This is important, a classic C compiler will discard any libraries listed there if there wasn't any object earlier in the list that depends on that variable.
Now that we know how to build a generic C program, we actually want to first build SCIP, then your program and link it. For that, we'll create a new PHONY dependency, called "all", that will do exactly that:
all: dep cmain
.PHONY: dep all
However, if we now execute make all it will fail as we haven't yet specified the include path etc. For that, we set the variables that we've used before to the needed values (I guessed the specific path, as I'm on mobile):
CPPFLAGS += -I$(SCIPDIR)/include
LDFLAGS += -L$(SCIPDIR)
LDLIBS += -lscip
Putting it all together
Now this should work, more or less. One thing though is, that it's common to have all as the default target, that is, the first target listed in the Makefile. So we write:
CPPFLAGS += -I$(SCIPDIR)/include
LDFLAGS += -L$(SCIPDIR)
LDLIBS += -lscip
all: dep cmain
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
%: %.o
$(CC) $(LDFLAGS) $(CFLAGS) -o $# $^ $(LDLIBS)
dep:
cd $(SCIPDIR); ./configure.sh
$(MAKE) -C $(SCIPDIR)
.PHONY: dep all
.SUFFIXES:
Note: I'm on mobile, so I couldn't test and don't know the exact paths, but this should guide you along. Also my code here used spaces instead of tabs in the Makefile for the same reason. Be sure to replace them.

Related

Correct way of installing postgresql extension with custom library

TL;DR
One has to compile their custom library as shared library:
gcc -c -fPIC warp_client.c -o warp_client.o
gcc -shared warp_client.o libwarp-client.so
Include the shared library and additional dependencies of that shared library in the Postgresql Makefile with the flags SHLIB_LINK and PG_LDFLAGS(Here the bachelor_fdw.c is the extension to compile):
EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql
OBJS = bachelor_fdw.o
PG_LIBS = -lpq
SHLIB_LINK = -lwarp_client -lucp
PG_LDFLAGS += -L/usr/lib/warpdrive/ -L/usr/lib/ucx/
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
Include the directories of the shared libraries into the environment variable LD_LIBRARY_PATH of Postgresql. For that, one has to add a line to the file 'environment' in the main Postgresql directory and restart Postgresql. Here is mine:
$ cat /etc/postgresql/12/main/environment
# environment variables for postgres processes
# This file has the same syntax as postgresql.conf:
# VARIABLE = simple_value
# VARIABLE2 = 'any value!'
# I. e. you need to enclose any value which does not only consist of letters,
# numbers, and '-', '_', '.' in single quotes. Shell commands are not
# evaluated.
LD_LIBRARY_PATH='/usr/include/:/usr/include/ucx/:/usr/lib/:/usr/lib/ucx/'
I am trying to create a foreign data wrapper, which uses a custom library from me. The fdw compiles and installs fine, but when using it, symbols to my library are undefined. What is the proper way of using custom c code as library in a postgresql extension and what am i doing wrong? Here are the steps i took:
Compile my library (warp_client.c) with flag -fPIC into an object file.
gcc -c -fPIC warp_client.c -o static/warp_client.o
Create static library from the object file.
ar -rcs out/libwarp_client.a static/warp_client.o
Copy libwarp_client.a and warp_client.h into the postgresql extension project root.
Compile postgresql extension with the following makefile.
EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql libwarp_client.a
OBJS = bachelor_fdw.o
HEADERS = warp_client.h
ifdef DEBUG
$(info $(shell echo "debug ist an"))
endif
PG_LIBS = -lpq
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
make USE_PGXS=1 install
Try to create the extension. The extension makes a call to a library function in it's _PG_INI() function. Error comes up:
CREATE EXTENSION IF NOT EXISTS bachelor_fdw;
psql:only_create.sql:3: ERROR: could not load library "/usr/lib/postgresql/12/lib/bachelor_fdw.so": /usr/lib/postgresql/12/lib/bachelor_fdw.so: undefined symbol: warpclient_getData
The warp_client.h has the function headers and warp_client.c has the functions. warp_client.c includes "warp_client.h", bachelor_fdw.c (the extension) includes "warp_client.h".
warp_client.h:
#ifndef TEST_FIELD_UCP_WARP_CLIENT_H
#define TEST_FIELD_UCP_WARP_CLIENT_H
#include <ucp/api/ucp.h>
int warpclient_queryServer(char *server_addr_local, int port, int useINet6, char *query);
void *warpclient_getData();
int warpclient_cleanup();
#endif //TEST_FIELD_UCP_WARP_CLIENT_H
Any more desired info? I would be really glad for any help.
EDIT 1
I use the functions from warp_client.h inside of bachelor_fdw.c. Do i still need to export them? I thought only functions, which get called from the postgresql server needs to be exported.
Here is part of bachelor_fdw.c:
#include <warp_client.h>
#include "postgres.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "nodes/nodes.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
...
PG_MODULE_MAGIC;
/*
* SQL functions
*/
PG_FUNCTION_INFO_V1(bachelor_fdw_handler);
PG_FUNCTION_INFO_V1(bachelor_fdw_validator);
/*
* Extension initialization functions
*/
extern void _PG_init(void);
extern void _PG_fini(void);
/*
* FDW callback routines
*/
static void bachelorBeginForeignScan(ForeignScanState *node, int eflags);
static TupleTableSlot *bachelorIterateForeignScan(ForeignScanState *node);
static void bachelorReScanForeignScan(ForeignScanState *node);
static void bachelorEndForeignScan(ForeignScanState *node);
static void bachelorGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
static void bachelorGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
static ForeignScan* bachelorGetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan);
void _PG_init(void){
int ret = 0;
void *data;
ret = warpclient_queryServer(NULL, -1, 0, "SELECT TEST FROM TEST;");
elog_debug("Testquery for server. Return code (%d)...\n", ret);
while(NULL != (data = warpclient_getData())){
elog_debug("Data received as fdw: %s\n", data);
}
elog_debug("Finished receiving data.\n");
/* Call cleanup */
ret = warpclient_cleanup();
elog_debug("Warpclient cleanup (%d)...\n", ret);
}
And here is part of warp_client.c:
#include "warp_client.h"
...
int warpclient_cleanup(){
int ret = 0;
//free buffers
free(recvbuffer->buffer);
free(recvbuffer);
/* Close the endpoint to the server */
debugmsg("Close endpoint.\n");
ep_close();
/* releasing UCX ressources */
ucp_worker_destroy(ucp_worker);
ucp_cleanup(ucp_context);
return ret;
}
int warpclient_queryServer(char *server_addr_local, int port, int useINet6, char *query){
/*
* Initialize important connection variables
*/
debugmsg("Initializing connection variables...\n");
if(NULL != server_addr_local) server_addr = server_addr_local;
if((port >= 0) && (port <= UINT16_MAX)) server_port = port;
if(useINet6) ai_family = AF_INET6;
int ret;
/* Initialize the UCX required objects worker and context*/
debugmsg("Initializing context and worker...\n");
ret = init_context_and_worker();
if (ret != 0) {
fprintf(stderr, "Initializing worker or context failed! Exiting..\n");
return -2;
}
/*
* UCP objects: client_ep as communication endpoint for the worker.
* status for function error code check.
*/
ucs_status_t status;
/* ep initialization and exchange with server over sockets */
debugmsg("Creating Client endpoint.\n");
status = create_client_endpoint();
if (status != UCS_OK) {
fprintf(stderr, "failed to start client (%s)\n", ucs_status_string(status));
return -1;
}
ret = send_query(query);
if(ret!=0){
debugmsg("Failed to connect to Server.\n");
}
return ret;
}
EDIT 2
I managed to get a good step forward thanks to Laurenz Albe. But i still have a problem with a shared library used in my shared library. Do I also need to link to shared libraries used in my own shared library, even though i linked that as i compiled my shared library before distribution?
what I did:
I added SHLIB_LINK = -lwarp_client to the Makefile and also needed the line PG_LDFLAGS += -L. for the linker to find libwarp_client.so.
I also managed to include the environment variable LD_LIBRARY_PATH for the postgres service, so that it can find my library in the standard places. And removed the library from the DATA flag in the Makefile.
New Makefile:
EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql
OBJS = bachelor_fdw.o
ifdef DEBUG
$(info $(shell echo "debug ist an"))
endif
PG_LIBS = -lpq
SHLIB_LINK = -lwarp_client
PG_LDFLAGS += -L.
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
Enrivonment variables:
/proc/1551/environ | xargs -0 -n 1 echo
LD_LIBRARY_PATH=/usr/include/:/usr/include/ucx/:/usr/lib/:/usr/lib/ucx/
...
When using CREATE on the extension, my library gets used but postgres complains about another shared library, which my library uses.
psql:only_create.sql:3: ERROR: could not load library "/usr/lib/postgresql/12/lib/bachelor_fdw.so": /usr/lib/warpdrive/libwarp_client.so: undefined symbol: ucp_ep_create
The error clearly says, it uses my shared library from a subdirectory "warpdrive" in the included standard directory. The shared library from UCP is also in that standard directory:
ls /usr/lib/ucx
cmake libjucx.so.0.0.0 libucp.a libucs.la libuct.so
jucx-1.12.1.jar libucm.a libucp.la libucs.so libuct.so.0
libjucx.a libucm.la libucp.so libucs.so.0 libuct.so.0.0.0
libjucx.la libucm.so libucp.so.0 libucs.so.0.0.0 pkgconfig
libjucx.so libucm.so.0 libucp.so.0.0.0 libuct.a ucx
libjucx.so.0 libucm.so.0.0.0 libucs.a libuct.la
That looks like warpclient_getData gets used in your code, but you didn't link your shared object with the library that provides the function. Add the library to the SHLIB_LINK variable:
SHLIB_LINK = -lwarp
(That example assumes a library called libwarp.so.)

How to compile program with OpenSSL on Windows with MinGW

I tried running this sample code from fm4dd.com. But I don't know how to actually include the header files into my program.
Orignally it was like:
#include <openssl/bio.h>
But i changes it to their actual path, but an error still shows up.
#include <C:\openssl\include\openssl\bio.h>
#include <C:\openssl\include\openssl\err.h>
#include <C:\openssl\include\openssl\pem.h>
#include <C:\openssl\include\openssl\x509.h>
#include <C:\openssl\include\openssl\e_os2.h>
int main() {
const char cert_filestr[] = "./cert-file.pem";
EVP_PKEY *pkey = NULL;
BIO *certbio = NULL;
BIO *outbio = NULL;
X509 *cert = NULL;
int ret;
/* ---------------------------------------------------------- *
* These function calls initialize openssl for correct work. *
* ---------------------------------------------------------- */
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
/* ---------------------------------------------------------- *
* Create the Input/Output BIO's. *
* ---------------------------------------------------------- */
certbio = BIO_new(BIO_s_file());
outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
/* ---------------------------------------------------------- *
* Load the certificate from file (PEM). *
* ---------------------------------------------------------- */
ret = BIO_read_filename(certbio, cert_filestr);
if (! (cert = PEM_read_bio_X509(certbio, NULL, 0, NULL))) {
BIO_printf(outbio, "Error loading cert into memory\n");
exit(-1);
}
/* ---------------------------------------------------------- *
* Extract the certificate's public key data. *
* ---------------------------------------------------------- */
if ((pkey = X509_get_pubkey(cert)) == NULL)
BIO_printf(outbio, "Error getting public key from certificate");
/* ---------------------------------------------------------- *
* Print the public key information and the key in PEM format *
* ---------------------------------------------------------- */
/* display the key type and size here */
if (pkey) {
switch (pkey->type) {
case EVP_PKEY_RSA:
BIO_printf(outbio, "%d bit RSA Key\n\n", EVP_PKEY_bits(pkey));
break;
case EVP_PKEY_DSA:
BIO_printf(outbio, "%d bit DSA Key\n\n", EVP_PKEY_bits(pkey));
break;
default:
BIO_printf(outbio, "%d bit non-RSA/DSA Key\n\n", EVP_PKEY_bits(pkey));
break;
}
}
if(!PEM_write_bio_PUBKEY(outbio, pkey))
BIO_printf(outbio, "Error writing public key data in PEM format");
EVP_PKEY_free(pkey);
X509_free(cert);
BIO_free_all(certbio);
BIO_free_all(outbio);
exit(0);
}
but the following error shows up every time I try to compile it on the command prompt. Since, I'm a noob, I have no clue how to proceed from here and what to do to fix this error.
c:\openssl>gcc -lssl -lcrypto -o test test.c
In file included from test.c:1:0:
C:\openssl\include\openssl\bio.h:62:27: fatal error: openssl/e_os2.h: No such file or directory
#include <openssl/e_os2.h>
^
compilation terminated.
Edit:
I included the solution to the problem, but now a new error showed up:
c:\openssl>gcc -lssl -lcrypto -o test test.c -IC:\openssl\include\
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find -lssl
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find -lcrypto
collect2.exe: error: ld returned 1 exit status
In many cases, include-files in turn include other files. The paths of these files are specified relative, not absolute. So you have to tell your compiler, where to search for include files in general.
The -I-option is for this purpose and tells the compiler, which paths (additionally to some standard paths) are to be searched for specified include files, in your case you would use:
gcc -I C:\openssl\include
If you really need to specify an absolute include path you would use quotes, not <>, i.e.
#include "C:\foo\bar\baz.h"
but if this file includes other files, the compiler will not look specifically into C:\foo\bar for these.
Get rid of the full path names in your #include directives. That is, don't use #include <C:\openssl\include\openssl\bio.h>; rather, use:
#include <openssl\bio.h>
#include <openssl\err.h>
#include <openssl\pem.h>
#include <openssl\x509.h>
#include <openssl\e_os2.h>
And pass the include directory to gcc with -I:
gcc -I c:\openssl\include -o myfile myfile.c -lcrypto

How to compile and link C and ASM together on Windows for my OS

I have a problem with my 32-bit protected mode OS project Sinatra. I can compile sources to object files, but I don't know how to link these together. I use NASM and TDM-GCC on Windows. I have fixed problems with my code so it compiles. I have removed the comments for brevity.
My file boot.asm:
[BITS 32]
[global start]
[extern _JlMain]
start:
cli
call _JlMain
hlt
My file JSinatra.h:
#ifndef __SINATRA_H__
#define __SINATRA_H__
#define JWhiteText 0x07
void JlMain();
void JlClearScreen();
unsigned int JlPrintF(char * message, unsigned int line);
#endif
My file JSinatra.c:
#include "JSinatra.h"
void JlClearScreen() // clear entire screen
{
char * vidmem = (char * ) 0xb8000;
unsigned int i = 0;
while (i < (80 * 25 * 2)) {
vidmem[i] = ' ';
i += 1;
vidmem[i] = JWhiteText;
i += 1;
}
}
unsigned int JlPrintF(char * message, unsigned int line) {
char * vidmem = (char * ) 0xb8000;
unsigned int i = 0;
i = line * 80 * 2;
while ( * message != 0) {
if ( * message == '\n') {
line += 1;
i = (line * 80 * 2); * message += 1;
} else {
vidmem[i] = * message; * message += 1;
i += 1;
vidmem[i] = JWhiteText;
i += 1;
}
}
return (1);
}
void JlMain() {
JlClearScreen();
JlPrintF("Sinatra v0 Virgin/Kernel Mode\n", 0);
}
I need to load my OS starting at absolute address 0x100000. How can I properly compile and link my code to create a binary image?
First of all, if you're compiling to ELF, then you mustn't add an initial underscore before functions in assembly.
Now, in order to link different source files together, you obviously have to get them to common ground, which is in this case, object code.
So, what you'll do is:
Assemble the assembly source files to object code.
Compile but not link C source files to object code. In gcc: gcc -c file.c -o file.o
Link those together. In gcc: gcc cfile.o asfile.o -o app
Using GCC-TDM and NASM on Windows
Because you are targeting an OS being loaded at an absolute address without C-runtimes you'll need to make sure you compile as freestanding code; that your asm and C files target the same type of object (win32/PECOFF); and the last step will be converting the PECOFF file to a binary image.
To compile C files you would use something like:
gcc -m32 -ffreestanding -c JSinatra.c -o JSinatra.o
To assemble the asm files you would use something like:
nasm -f win32 boot.asm -o boot.o
To link them together you have to do it in two steps:
ld -m i386pe -T NUL -o sinatra.tmp -Ttext 0x100000 boot.o JSinatra.o
The ld command above will create a temporary file sinatra.tmp that is a 32-bit PECOFF executable. You then need to convert sinatra.tmp to a binary image with a command like:
objcopy -O binary sinatra.tmp sinatra.img
You should then have a binary image in the file sinatra.img

Issues with make and #include

Somewhere between my headers and my Makefile I'm not doing the dependencies correctly, and it's not compiling. This really only has anything to do with the first few lines from each code, but I posted all the code for reference
I'm trying to split up a who clone into 3 parts. Here is the original for reference. The exercise is to make it with utmp, so you also need utmplib
So I've split it up into 3 files, the first one being show.h
#include <stdio.h>
#include <sys/types.h>
#include <utmp.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#define SHOWHOST
void show_info(struct utmp *);
void showtime(time_t);
then I have show.c
/*
* * show info()
* * displays the contents of the utmp struct
* * in human readable form
* * * displays nothing if record has no user name
* */
void show_info( struct utmp *utbufp )
{
if ( utbufp->ut_type != USER_PROCESS )
return;
printf("%-8.8s", utbufp->ut_name); /* the logname */
printf(" "); /* a space */
printf("%-8.8s", utbufp->ut_line); /* the tty */
printf(" "); /* a space */
showtime( utbufp->ut_time ); /* display time */
#ifdef SHOWHOST
if ( utbufp->ut_host[0] != '\0' )
printf(" (%s)", utbufp->ut_host); /* the host */
#endif
printf("\n"); /* newline */
}
void showtime( time_t timeval )
/*
* * displays time in a format fit for human consumption
* * uses ctime to build a string then picks parts out of it
* * Note: %12.12s prints a string 12 chars wide and LIMITS
* * it to 12chars.
* */
{
char *ctime(); /* convert long to ascii */
char *cp; /* to hold address of time */
cp = ctime( &timeval ); /* convert time to string */
/* string looks like */
/* Mon Feb 4 00:46:40 EST 1991 */
/* 0123456789012345. */
printf("%12.12s", cp+4 ); /* pick 12 chars from pos 4 */
}
and finally, `who3.c'
/* who3.c - who with buffered reads
* - surpresses empty records
* - formats time nicely
* - buffers input (using utmplib)
*/
#include "show.h"
int main()
{
struct utmp *utbufp, /* holds pointer to next rec */
*utmp_next(); /* returns pointer to next */
if ( utmp_open( UTMP_FILE ) == -1 ){
perror(UTMP_FILE);
exit(1);
}
while ( ( utbufp = utmp_next() ) != ((struct utmp *) NULL) )
show_info( utbufp );
utmp_close( );
return 0;
}
So I created my Makefile:
who3:who3.o utmplib.o
gcc -o who who3.o utmplib.o
who3.o:who3.c show.c
gcc -c who3.c show.o
show.o:show.c
gcc -c show.c show.h
utmplib.o:utmplib.c
gcc -c utmplib.c
clean:
rm -f *.o
Unfortunately there's an error when I do make:
gcc -o who who3.o utmplib.o
who3.o: In function `main':
who3.c:(.text+0x38): undefined reference to `show_info'
collect2: error: ld returned 1 exit status
make: *** [who3] Error 1
As I said earlier, I haven't done my dependencies correctly, and I'm not sure what I did wrong. How do I do my dependencies correctly?
It looks like you are missing show.o from the dependencies and from the list of object files of the command for building who3 in your makefile.
Also, the command for who3.o looks wrong. You are compiling only -c, but you are passing an object file as input (show.o). You should remove show.o from the rule and show.c doesn't belong on the list of dependencies of who3.o either.
Also, the command for show.o looks wrong. You shouldn't be passing header files (show.h) to the compiler; they only need to be referenced as #include in the source files.
Also, you are inconsistent about what your default is actually called. You say it is who3 in the rule (who3: ...) but the command will actually build a task called who (gcc -o who ...).

Compiling a C program

i am trying to compile this code, but if i do using:
gcc prt.c portaudio.h -o prt
but i get this error:
main.c:47: undefined reference to `Pa_OpenDefaultStream'
main.c:62: undefined reference to `Pa_StartStream'
main.c:65: undefined reference to `Pa_Sleep'
main.c:66: undefined reference to `Pa_StopStream'
main.c:69: undefined reference to `Pa_CloseStream'
main.c:72: undefined reference to `Pa_Terminate'
main.c:78: undefined reference to `Pa_Terminate'
i don't know why, then i though it might be beacuse i don't have a rule (make file)
so i made one:
main: main.o
gcc main.o -o main
main.o: main.c portaudio.h
gcc -c main.c
but when i try to run it through cygwin: using "Make"
i get this message:
"make: *** No targets specified and no makefile found. Stop.
I don't understand the problem, please help me is something wrong with my makefile or is there something else wrong.
also this is the code:
main.c
#include <stdio.h>
#include "portaudio.h"
#define SAMPLE_RATE (44100)
typedef struct
{
float left_phase;
float right_phase;
}
paTestData;
static int patestCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
/* Cast data passed through stream to our structure. */
paTestData *data = (paTestData*)userData;
float *out = (float*)outputBuffer;
unsigned int i;
(void) inputBuffer; /* Prevent unused variable warning. */
for( i=0; i<framesPerBuffer; i++ )
{
*out++ = data->left_phase; /* left */
*out++ = data->right_phase; /* right */
/* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
data->left_phase += 0.01f;
/* When signal reaches top, drop back down. */
if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
/* higher pitch so we can distinguish left and right. */
data->right_phase += 0.03f;
if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
}
return 0;
}
static paTestData data;
int main (void) {
PaStream *stream;
PaError err;
err = Pa_OpenDefaultStream( &stream,
0, /* no input channels */
2, /* stereo output */
paFloat32, /* 32 bit floating point output */
SAMPLE_RATE,
256, /* frames per buffer, i.e. the number
of sample frames that PortAudio will
request from the callback. Many apps
may want to use
paFramesPerBufferUnspecified, which
tells PortAudio to pick the best,
possibly changing, buffer size.*/
patestCallback, /* this is your callback function */
&data ); /*This is a pointer that will be passed to
your callback*/
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
Pa_Sleep(9*1000);
err = Pa_StopStream( stream );
if( err != paNoError ) goto error;
err = Pa_CloseStream( stream );
if( err != paNoError ) goto error;
err = Pa_Terminate( );
if( err != paNoError ) goto error;
printf("Test finished.\n");
return err;
error:
Pa_Terminate();
return err;
}
and the header file portaudio.h: Portaudio.h
if you want cleaner view of main.c: main.c
I am not so sure why these messages/errors/warning are coming, please help.
also this is my folder view:
You seem to be using functions from a library for the 'Port Audio' facility, but your link line does not tell the C compiler how to find that library - so the functions show up as undefined references.
Your link line should look something like:
gcc -o main main.o -lpa
That should be macroized, but the gist is correct.
This assumes the library is in 'libpa.a' or thereabouts. If it is in 'libportaudio.so', then use -lportaudio instead of -lpa.
Using macros in the makefile:
PROGRAM = main
SOURCE = main.c
OBJECT = $(SOURCE:.c=.o)
LIBDIR = /cygdrive/c/installdir/portaudio/lib
LIBRARY = $(LIBDIR)/portaudio_x86.lib
$(PROGRAM): $(OBJECT)
$(CC) $(CFLAGS) -o $# $(OBJECT) $(LDFLAGS) $(LIBRARY)
main.o: main.c portaudio.h
You should not need an explicit compilation command for main.o; make should be able to deduce that from its internal rules. Note that the character before $(CC) must be a TAB and not spaces.
The make command only looks for a file called makefile or Makefile, to use make with a differently named makefile, you need to do make -f otherfile target.
Rename your file Make file to Makefile to have make look at its contents. Also, verify that you use one tab character (no spaces) in all of the commands under a target. You might have done that, but your cut-and-paste of the contents in this posting doesn't let us know if that is really how it is.
It would also appear that you need the PortAudio library to link to or those functions will not be defined. That is, unless they're defined in the header (I haven't used that library before...)
Did portaudio come with a .lib or anything? The header file only contains the name of the functions, not the definitions. You'll need to link against the library to get the functionality for all of those functions
Your initial problem ("Undefined reference to...") is a message from the linker saying it cannot find a definition of the functions mentioned. This means you need to add a linker argument saying that you want to add the library providing these functions (lib portaudio?) to your program. GCC's command line parameter to do so is "-l"
It seems like you need to include the library (with a -l[library name] option.
A search of portaudio compile commands shows libportaudio.a included in the gcc options.
You are probably not linking to those libraries libs (.so or .a) look at the documentation and see what libs you need to link your program with.
The other thing is that when you run "make -f Makefile" you need to have a tab in your makefile before the "gcc..." lines i.e. the command lines.
I also need to add -lm, otherwise it throws an error.
So gcc -o test test.c -lm -lportaudio

Resources