Reputation: 11
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
Upvotes: 1
Views: 316
Reputation: 291
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.
Upvotes: 2