1

I've several files with main functions in C, for example, I've files called show.c, delete.c add.c (...). I also have a file, called interpreter.c, which may call one of the files, for example delete.c. Most of these file implement a main function, like the delete.c:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

int main (int argc, char *argv[]) 
{
    int fd, rm;
    char *caminho = argv[1]; // argumento inserido no terminal
    char caminhod[30]="../TPSOFinal/";

    strcat(caminhod,argv[1]);
    
    fd = open(caminhod, O_RDONLY);

    rm=unlink(caminhod);

    // Verifica se o caminho inserido no input existe
    if(rm == 0){
        write(1,"Ficheiro eliminado!!!\n", 22);
        return 0;
    }
    else{
        write(1,"Erro ao eliminar ficheiro !!!\n", 29);
        perror("Erro");
    }
    
    return 0;
    close(fd);
}

The interpreter:

#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <readline/readline.h>
#include <readline/history.h>


#define LER_BUFFER 1024
#define TBUFF 64
#define DELIM "\t\r\n\a"

int mostra(char **args);
int conta(char **args);
int acrescenta(char **args);
int apaga(char **args);
int informa(char **args);
int lista(char **args);
int manual(char **args);
int termina(char **args);


char *comando[] =
{
    "mostra <caminho>",
    "conta  <caminho>",
    "acrescenta <caminho> <caminho destino>",
    "apaga <caminho>",
    "informa <caminho>",
    "lista <caminho>",
    "manual",
    "termina",
    " ",
};


int (*fcomandos[]) (char**) =
{
    &mostra,
    &conta,
    &acrescenta,
    &apaga,
    &informa,
    &lista,
    &manual,
    &termina
};
    
int ncomandos()
{
    return sizeof(comando)/sizeof(char*);
}


void processa(char *linha, char **argv)
{
    while(*linha != '\0')
    {
        while(*linha == ' ' || *linha == '\t' || *linha == '\n')
        {
            *linha++ = '\0';      //troca caracteres especiais
        }
        *argv++ = linha;              //guarda posição

        while (*linha != '\0' && *linha != ' ' && *linha != '\t' && *linha != '\n')
        {
            linha++;
        }
    }
    *argv = NULL;
}
char *lerlinha (void)
{
    char *linha = NULL;
    ssize_t tam = 0;
    getline (&linha, &tam, stdin);

    return linha;
}

char **separa (char *linha)
{
    int tam = TBUFF, pos = 0;
    char **palavras = malloc (tam *sizeof(char*));
    char *palavra;

    if (!palavras)
    {
        perror("Erro");
        exit(EXIT_FAILURE);
    }
    
    palavra = strtok (linha, DELIM);

    while (palavra != NULL)
    {
        palavras [pos] = palavra;
        pos ++;
        
        if (pos >= tam)
        {
            perror ("Erro");
        }
        
    }
    palavra = strtok(NULL, DELIM);
    
    palavras [pos] = NULL;
    return palavras;
}

int launch (char **args)
{
    pid_t pid, wpid;
    int estado;

    pid = fork();
    
    if (pid == 0)
    {
        if(execvp(args[0],args)==-1){ perror ("Erro!"); }
        
        exit (EXIT_FAILURE);
    }

    if (pid <0)
    {
        perror ("Erro!");
    }
    else
    {
        do{wpid = waitpid(pid, &estado, WUNTRACED);}
        while (!WIFEXITED(estado)&& !WIFSIGNALED(estado));
    }

    return 1;

    
}
//Testa se os comandos existem
int mostra (char **args)
{
    if (args[1] == NULL)
    {
        perror("sem argumentos ");
    }
    else if (chdir (args[1]) != 0)
    {
        perror ("Erro!");
    }
    return 1;
}

int conta ( char ** args)
{
    if (args[1] == NULL)
    {
        perror("Sem argumentos "); 
    }
    else if (chdir (args[1])!= 0)
    {
        perror ("Erro!");
    }
    return 1;
}

// Manual dos comandos
int manual (char **args)
{
    int i;
    printf("\n\nMiguel Oliveira\n");
    printf("10260 - LESI\n");
    printf("Sistemas Operativos e Sistemas Distribuidos\n");
    printf("\nLista de Comandos\n");

    for (i=0; i<ncomandos(); i++)
    {
        printf("%s\n", comando[i]);
    }
    return 1;
}

int termina (char **args)
{
    return 0;
}


//Executa os comandos
int executar (char **args)
{
    int i;
    
    if (args[0] == NULL)
    {
        return 1;
    }

    for (i=0; i<ncomandos(); i++)
    {
        if (strcmp(args[0], comando[i])==0)
        {
            return (*fcomandos[i])(args);
        }
    }
    return launch(args);
}

//Interpretador
void  interpretador (void)
{
    char  *linha;             
    char  **args;
    int estado;            

    do
    {                   
        printf("%% "); 
        linha = lerlinha();
        args = separa(linha);
        estado = executar(args);

        free(linha);
        free(args);  
        
    } while (estado);
}

int main (void)
{
    interpretador();

    return EXIT_SUCCESS;
}

I've tried to research for similar problems, and i've found some little possible solutions, but cannot solve my problem, as show on bottom GCC compile mistake

6
  • Please post the error in the question and probably translate it to english. Commented Jul 10, 2020 at 23:06
  • 3
    Where do you implement acrescenta, apaga, informa and lista? Commented Jul 10, 2020 at 23:37
  • 2
    Please do not post pictures of text, instead, copy and paste the text into your question (indented by 4-spaces or wrapped in ``` so it formats as fixed-text). What would have taken ~240-bytes to store as text, requires 113.8 KB (116,529 bytes) to store as your image. Commented Jul 10, 2020 at 23:42
  • @Hal9000 I am following closely this work, because is a work made by a friend. We‘ve created a c file for any function, so for example the “apaga” which means delete it is in a specific C file. Congrats Commented Jul 11, 2020 at 0:50
  • We’ve researched for similar problems and tried to solve that, but without any success. Commented Jul 11, 2020 at 0:56

1 Answer 1

2

You do not "call source files"; source files define functions and variables, and when compiled, ones defined in different files can use each other if they have a declaration (in a header file, usually) or a pointer (via dynamic link methods, like POSIX dlsym()).

Consider this minimal example. First, example.c:

#include <stdlib.h>
#include <stdio.h>

/* We expect someone else to define these */
extern int one(void);

int main(void)
{
    printf("one() returned %d.\n", one());
    return EXIT_SUCCESS;
}

and helper.c:

int one(void)
{
    return 2;  /* TODO: It's not one! */
}

You compile each source file to an object file:

gcc -Wall -O2 -c example.c
gcc -Wall -O2 -c helper.c

and then you link them to an executable program:

gcc -Wall -O2 example.o helper.o -o program

which you can run using

./program

Normally, each C source file that provides functions or variables usable outside that file, declares them in a header file. Here's a better example.

degrees.h

#ifndef   DEGREES_H
#define   DEGREES_H

double radians_to_degrees(double);
double degrees_to_radians(double);

#endif /* DEGREES_H */

The #ifndef, #define, and #endif are used as guards, so that if you #include the file more than once, the functions get declared only once. (The compiler will complain if it sees multiple declarations. Plus, we don't need to use extern here.)

The implementation of the above is then in degrees.c,

#ifndef  PI
#define  PI  3.14159265358979323846
#endif

double  degrees_to_radians(double degrees)
{
    return degrees * PI / 180.0;
}

double  radians_to_degrees(double radians)
{
    return radians * 180.0 / PI;
}

In a program myprog.c in the same project, you would use the above thus:

#include <stdlib.h>
#include <stdio.h>
#include "degrees.h"

int main(void)
{
    printf("45 degrees is %.6f radians.\n", degrees_to_radians(45.0));
    printf("2 radians is %.3f degrees.\n", radians_to_degrees(2.0));
    return EXIT_SUCCESS;
}

and again you'd compile first the two source files to object files,

gcc -Wall -O2 -c degrees.c
gcc -Wall -O2 -c myprog.c

and then link together to a program, say myprog,

gcc -Wall -O2 degrees.o myprog.o -o myprog

which you can then run:

./myprog

It is also possible to compile and link the functions and variables declared in degrees.h to a static (libdegrees.a) or a dynamic (libdegrees.so) library, and install the header file to the standard location, so that your program could instead use #include <degrees.h> and the program link to the library via -ldegrees, but that is better left until you are well comfortable working with multiple files.

Until then, you might find the following Makefile useful

CC      := gcc
CFLAGS  := -Wall -O2
LDFLAGS :=
PROGS   := myprog

all: clean $(PROGS)

clean:
    rm -f *.o $(PROGS)

%.o: %.c
    $(CC) $(CFLAGS) -c $^

myprog: degrees.o myprog.o
    $(CC) $(CFLAGS) $^ -o $@

You can add multiple programs in the PROGS line, separated by spaces, and copy the myprog: lines for each, listing the object files that program needs.

With this, all you need to compile the program is to type make.

This forum eats Tabs, and Makefiles need indentation to use those. So, if you just copy-paste that to a file, it won't work. You can fix it, though, by running

sed -e 's|^  *|\t|' -i Makefile

which removes all initial spaces on each line with a tab in file Makefile.

If you use separate libraries, typically libm (#include <math.h>), you just need to add -lm (dash ell em) to the LDFLAGS line. If you eventually play with dynamic linking, that's -ldl.

If you were to write a graphical program using Gtk+, you'd append `pkg-config --cflags gtk+-3.0` (including the backticks `) to the CFLAGS line, and `pkg-config --libs gtk+-3.0` to the LDFLAGS line, and #include <gtk/gtk.h> to your program.

Sign up to request clarification or add additional context in comments.

5 Comments

Protip: %.o: %.c is an implicit rule, no need to define it.
You are right in that you can't "call" a source file. But it is perfectly possible to compile a source-file into an executable, and execute that. Which is probably what the poster means. This has nothing to do with his missing function definitions though. We don't know if those exist in a separate file or not.
@HAL9000: Of course; I just guessed differently at what the underlying conceptual problem OP has – that they didn't understand how sources, headers, object files, and executables relate to each other. And as you well know, one can even do multiple sources in a single pass, gcc -Wall -O2 myprog.c degrees.c -o myprog; I just thought it was better to do it in steps like that. If you believe my wording is misleading, please either edit, or suggest better wording! :)
@None, I don't think your wording is misleading. I think the question is. Looking at the interpreter, it is supposed to call both internal and external commands. So before we know where the missing functions are supposed to be, we can't say if the error is a linking problem, forgotten definitions, or trying to "call" a c-file.
Protip2: If you name one of your source-files correctly, there is an implicit rule for linking too. You just have to add additional dependencies.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.