Search code examples
clinuxubuntugccmakefile

Failing to execute "make" in Ubuntu gcc


I have several files which I'm trying to compile using gcc in Ubuntu. I have vmware machine 16.04 ubuntu, which 64-bit computer. I have added the flags for 32bit compilation in the makefile. (-m32 flag).

This is the makefile:

    all: clean binsem.a ut.a ph
FLAGS = -Wall  -L./ -m32


ph: ph.c
    gcc ${FLAGS} ph.c  -lbinsem -lut -o ph 


binsem.a:
    gcc $(FLAGS)  -c binsem.c
    ar rcu libbinsem.a binsem.o
    ranlib libbinsem.a 


ut.a:
    gcc $(FLAGS)  -c ut.c
    ar rcu libut.a ut.o
    ranlib libut.a 

clean:
    rm -f *.o 
    rm -f a.out
    rm -f *~
    rm -f ph
    rm -f *a 

My attempts to compile the code were not successful, as I received the following error:

ph.c:126:12: warning: ‘main’ defined but not used [-Wunused-function]
/usr/lib/gcc/i686-linux-gnu/5/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:6: recipe for target 'ph' failed
make: *** [ph] Error 1

**I tried - **

  1. Adding -c flags to the ph.c file in the make file. However it doesn't make much sense, since it has a main function. No success.
    1. Adding sum -m32 flags in the makefile, in addition to what's already written. No Success.

The file "ph.c", is the following file -

#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#include <sys/time.h>
#include <inttypes.h>

#include "binsem.h"
#include "ut.h"



#define LEFT  (i+N-1)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY   1
#define EATING   2

int N;

volatile int *phil_state;
sem_t *s;
sem_t mutex;
int *tid;

uint64_t get_wall_time() {
 struct timeval time;

 gettimeofday(&time, NULL); 
 uint64_t millis = (time.tv_sec * (uint64_t)1000) + (time.tv_usec / 1000);


 return millis;
}

void think(int p) {
  int i, factor;
  volatile int j;

  printf("Philosopher (%d) - time %" PRId64 " - is thinking\n",p, get_wall_time()); fflush (stdout);

  factor = 1 + random()%5;

  for (i = 0; i < 100000000*factor; i++){
    j += (int) i*i;
  }

  printf("Philosopher (%d) - time %" PRId64 " - is hungry\n", p, get_wall_time()); fflush (stdout);
}

void eat(int p){
  int i, factor;
  volatile int j;

   printf("Philosopher (%d) - time %" PRId64 " - is eating\n",p, get_wall_time()); fflush (stdout);

   factor = 1 + random()%5;
   for (i = 0; i < 100000000*factor; i++){
      j += (int) i*i;
   }
   //printf("Philosopher (%d) - time %" PRId64 " - is thinking\n",p, get_wall_time()); fflush (stdout);
}

void test(int i){
  if (phil_state[i] == HUNGRY &&
      phil_state[LEFT] != EATING &&
      phil_state[RIGHT] != EATING){
    phil_state[i] = EATING;

    binsem_up(&(s[i]));
  }
}

void take_forks(int i){
  binsem_down(&mutex);

  phil_state[i] = HUNGRY;

  test(i);

  binsem_up(&mutex);

  binsem_down(&(s[i]));
}


void put_forks(int i){
  binsem_down(&mutex);

  phil_state[i] = THINKING;

  test(LEFT);
  test(RIGHT);

  binsem_up(&mutex);
}

void int_handler(int signo) {
  long int duration;
  int i;

  for (i = 0; i < N; i++) {
    duration = ut_get_vtime(tid[i]);
    printf("Philosopher (%d) used the CPU %ld.%ld sec.\n",
       i+1,duration/1000,duration%1000);
  }
  exit(0);
}

void philosopher(int i){
  while (1){
    think(i);
    take_forks(i);
    eat(i);
    put_forks(i);
  }
}

static int main(int argc, char *argv[])
{
  int c;
  if (argc != 2){
    printf("Usage: %s N\n", argv[0]);
    exit(1);
  }

  N = atoi(argv[1]);

  if (N < 2){
    printf("Usage: %s N (N >=2)\n", argv[0]);
    exit(1);
  }

  ut_init(N);
  s = (sem_t *)malloc (N * sizeof(sem_t));
  phil_state = (int *) malloc (N * sizeof(int));
  tid = (int *) malloc (N * sizeof(int));

  for (c = 0; c < N ; c++){
    phil_state[c] = THINKING;
    binsem_init(&(s[c]), 0);
  }

  for (c = 0; c < N ; c++){
    tid[c] = ut_spawn_thread(philosopher,c);
    printf("Spawned thread #%d\n", tid[c]);
  }

  binsem_init(&mutex, 1);

  signal(SIGINT,int_handler);
  ut_start();

  return 0; // avoid warnings

}

The makefile also tries to compile these files - ut.c, binsem.c

#include <stdlib.h>
#ifndef _UT_H
#define _UT_H
#include "ut.h"
#include <sys/time.h> // for itimerval
#include <unistd.h> // for alarm
#include <stdlib.h> // for malloc
#include <stdio.h> // for perror
#include <ucontext.h>
# include "ut.h"
#define MAX_TAB_SIZE 128 // the maximal threads table size.
#define MIN_TAB_SIZE 2   // the minimal threads table size.
#define SYS_ERR -1       // system-related failure code
#define TAB_FULL -2      // full threads table failure code
/*This type defines a single slot (entry) in the threads table. Each slot describes a single
thread. Note that we don't need to keep the thread state since every thread is always ready
or running. We also don't have to support adding/stopping thread dynamically, so we also don't
have to manage free slots.*/
typedef struct ut_slot {
    ucontext_t uc;
    unsigned long vtime;  /* the CPU time (in milliseconds) consumed by this thread.*/
    void (*func)(int);    /* the function executed by the thread.*/
    int arg;              /* the function argument.*/
} ut_slot_t, *ut_slot;

static ut_slot threads; // pointer to thread table
static volatile int numThreads = 0; // number of threads in the table
static volatile int currentThread = 0; // current thread
static ucontext_t mainThread;


#define STACKSIZE 8192   // the thread stack size.

/* The TID (thread ID) type. TID of a thread is actually the index of the thread in the
   threads table. */
typedef short int tid_t;



void handler(int signal){
    alarm(1); //the alarm every second as demanded in the assignment
    currentThread = (currentThread +1 ) % numThreads;
    printf("in signal handler: switching from %d to %d\n", currentThread, currentThread - 1);
    swapcontext(&threads[currentThread].uc, &threads[currentThread].uc); /*save current thread,
*                                                                              load next thread*/
    if (signal == SIGVTALRM){ // increment the time stats
        threads[currentThread].vtime+=100;

    } else if(signal==SIGALRM) {
        if (swapcontext(&threads[currentThread - 1].uc, &threads[currentThread].uc) == -1) {
            perror("could not do swapping");
            exit(1);
        }
    }
}

int ut_init(int tab_size){

    /// (###)

    if(tab_size < MAX_TAB_SIZE) {
        threads = (ut_slot) malloc(tab_size * sizeof(int(ut_slot_t)));
    }
    else{
        threads = (ut_slot) malloc(MAX_TAB_SIZE * sizeof(int(ut_slot_t)));
    }
    if (!threads) {
        return SYS_ERR;
    }
    return 0;

}

tid_t ut_spawn_thread(void (*func)(int), int arg){
    /*uc[1].uc_link = &uc[0];
    uc[1].uc_stack.ss_sp = st1; //stack fro thread 1
    uc[1].uc_stack.ss_size = sizeof st1; //size of stack for therad
    makecontext(&uc[1], (void(*)(void)) f, 1, 1); */
    int thread_stack_size = STACKSIZE/8; //no need for 8K in size
    if (numThreads>=TAB_FULL){ //(*)
        return TAB_FULL;
    }
    if (getcontext(&threads[numThreads].uc)==-1){
        return SYS_ERR;
    }
    ut_slot_t newThread;
    threads[numThreads] = newThread;
    threads[numThreads].uc.uc_link = &mainThread;
    threads[numThreads].uc.uc_stack.ss_sp = (void* *)malloc(thread_stack_size);

    if(threads[numThreads].uc.uc_stack.ss_sp==NULL){
        return SYS_ERR;
    }
    makecontext(&threads[numThreads].uc,(void(*)(void))func,1,arg);
    numThreads++;

    return numThreads - 1;


}


int ut_start(void){
    struct sigaction sigaction1;
    int firstThread = 0; /*represents the current thread*/
    struct itimerval itv;
    /* set up vtimer for accounting */
    itv.it_interval.tv_sec = 0;
    itv.it_interval.tv_usec = 10000;
    itv.it_value = itv.it_interval;


    /* Initialize the data structures for SIGALRM handling. */
    sigaction1.sa_flags = SA_RESTART; //restart instead of throwing exception
    sigfillset(&sigaction1.sa_mask); // don't throw exception for additional signals
    sigaction1.sa_handler = handler; // specify handler for the sigaction declared

    if (sigaction(SIGVTALRM, &sigaction1, NULL) < 0)
        return SYS_ERR;
    /*START THE TIMER */
    if (setitimer(ITIMER_VIRTUAL, &itv, NULL) < 0)
        return SYS_ERR;

    if (sigaction(SIGINT, &sigaction1, NULL) < 0)
        return SYS_ERR;

    /* Start running. */

    alarm(1); //alarm every second
    if(swapcontext(&threads[firstThread].uc,&threads[firstThread+1].uc)==-1){ //swap first time
        return SYS_ERR;
    }

    return -1;
}


unsigned long ut_get_vtime(tid_t tid){
    return threads[tid].vtime;
}


#endif

binsem.c

#ifndef _BIN_SEM_H
#define _BIN_SEM_H

#include "binsem.h"
#include <signal.h>
#include "atomic.h"

typedef unsigned long sem_t;

void binsem_init(sem_t *s, int init_val){
    if(init_val == 1){
        *s = 1;
    }
    else{
        *s = 0;
    }
}

void binsem_up(sem_t *s){
    xchg(s,1); /*send the pointer of s, and the new value 1*/
}


int binsem_down(sem_t *s){
    int flag = 0;
    while (flag == 0){
        xchg(s,0); /*try changing the value - down*/
        if (*s != 0){  /*no success in changing*/
            if (raise(SIGALRM)!=0){ /*raise returns 0 on success*/
                return -1;
            }
        } else{
            flag = 1;
            return 0;
        }
    }

}

#endif

Any ideas?


Solution

  • You declare the main function to be static. That means it will have internal linkage, and not be exported. Therefore the linker will not be able to find it.

    Remove the static modifier and that should work.


    However there are also many other problems in your Makefile that will most likely lead to problems:

    The target ph only depends on ph.c, not the libraries you want to link with. You need to add the libraries as dependencies as well (their full file-names).

    You should also make the libraries depend on the object files used to create them, and rely on the implicit rules to build object files from source files.

    Also note that for a library named A then the file-name needs to be libA.a, otherwise the linker will not be able to find it with the -l (lower-case L) option.