2016-01-29 2 views
2

Я создаю простую оболочку в C, которая может выполнять команды, выполнять перенаправления и протоколы stdout. До сих пор я получил только часть перенаправления, но по какой-то причине, когда я пытаюсь скомпилировать collect2, выдает ошибку.Создание простой оболочки в C приводит к ошибке связывания

Файл util.c, что я в том числе:

#include<stdio.h> 
#include<unistd.h> 
#include<stdlib.h> 
#include<string.h> 
#include<signal.h> 
#include<errno.h> 
#include"util.h" 


void setSigHandler(){ 
    void (*oldHandler)(); 

    oldHandler = signal(SIGINT, SIG_IGN); 
    signal(SIGTERM, oldHandler); 
} 

void prompt(){ 
    char* user = getlogin(); 
    printf("[%s]-->$", user); 
} 

void getNextCommand(){ 
    errno = 0; 
    cmd = malloc(sizeof *cmd); 
    if(cmd == NULL){ 
     char* error = strerror(errno); 
     printf("malloc:%s\n", error); 
     exit(EXIT_FAILURE); 
    } 

    fgets(cmd->payload, sizeof(cmd->payload), stdin); 

    if(cmd->payload[strlen(cmd->payload) - 1] == '\n'){ 
     cmd->payload[strlen(cmd->payload) - 1] = '\0'; 
    } 
} 

void parseCommandString(){ 
    cmd->payloadArgc = 0; 
    char* buffer = strtok(cmd->payload, " "); 
    while(buffer != NULL){ 
     cmd->payloadArgv[cmd->payloadArgc] = buffer; 
     if(!strcmp(cmd->payloadArgv[cmd->payloadArgc], ">")){ 
      cmd->payloadArgv[cmd->payloadArgc] = NULL; 
      fileName = strtok(NULL, " "); 
      break; 
     } 
     if(!strcmp(cmd->payloadArgv[cmd->payloadArgc], "|")){ 
      cmd->payloadArgv[cmd->payloadArgc] = NULL; 
      pCount++; 
      break; 
     } 
     buffer = strtok(NULL, " ");  
     cmd->payloadArgc++; 
    } 
} 

И мой главный файл:

#include<stdio.h> 
#include<stdlib.h> 
#include<unistd.h> 
#include<string.h> 
#include<errno.h> 
#include<signal.h> 
#include<sys/file.h> 
#include<fcntl.h> 
#include"util.h" 

int execCommand(); 

int main(){ 
    setSigHandler(); 

    while(1){ 
     prompt(); 
     getNextCommand(); 

     //pdsh exits on "close" 
     if(!strcmp(cmd->payloadArgv[0], "close")) break; 

     parseCommandString(); 

    } 

    return 0; 
} 

int execCommand() 
{ 
    errno = 0; 
    int newFd; 

    // Fork process 
    pid_t pid = fork(); 

    // Error 
    if (pid == -1) { 
     char* error = strerror(errno); 
     printf("fork: %s\n", error); 
     return -1; 
    } 

    // Child process 
    else if (pid == 0) { 
     if(fileName != NULL){ 
      newFd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0755); 
      if(newFd == -1){ 
       char* error = strerror(errno); 
       printf("open: %s\n", error); 
       return -2; 
      } 
      dup2(newFd, STDOUT_FILENO); 
      close(newFd); 
     } 

     // Execute command 
     execvp(cmd->payloadArgv[0], cmd->payloadArgv); 

     // Error occurred 
     char* error = strerror(errno); 
     printf("shell: %s: %s\n", cmd->payloadArgv[0], error); 
     return -2; 
    } 

    // Parent process 
    else { 
     close(newFd); 
     fileName = NULL; 

     // Wait for child process to finish 
     int childStatus; 
     waitpid(pid, &childStatus, 0); 
     return 0; 
    } 
} 

и ошибка из collect2:

/tmp/ccIXS72e.o:(.bss+0x0): multiple definition of `fileName' 
/tmp/ccINCcwP.o:(.bss+0x0): first defined here 
/tmp/ccIXS72e.o:(.data+0x0): multiple definition of `pCount' 
/tmp/ccINCcwP.o:(.data+0x0): first defined here 
/tmp/ccIXS72e.o:(.data+0x4): multiple definition of `newDescriptor' 
/tmp/ccINCcwP.o:(.data+0x4): first defined here 
collect2: error: ld returned 1 exit status 

Что является причиной этого ?

Я знаю, что мой код main.c немного уродлив извините за это.

Edit: util.h по запросу:

#ifndef UTIL_H_ 
#define UTIL_H_ 

#define TRUE 1 
#define FALSE !TRUE 
#define STDOUT 0 
#define STDIN 1 
#define MAX_CMD_LENGHT 500 
#define MAX_CMD_ARGS_LENGHT 50 

char* fileName = NULL; 
int pCount = -1; 
int newDescriptor = -1; 

Command cmd; 


typedef struct commandR* Command; 
struct commandR{ 
    char payload[MAX_CMD_LENGHT]; 
    char* payloadArgv[MAX_CMD_ARGS_LENGHT]; 
    int payloadArgc; 
}; 

void setSigHandler(); 

void prompt(); 

void getNextCommand(); 

void parseCommand(); 


#endif 

Edit 2: После предложения я изменил мой код. Ошибка по-прежнему отключается.

util.h

#ifndef UTIL_H_ 
#define UTIL_H_ 

#define TRUE 1 
#define FALSE !TRUE 
#define STDOUT 0 
#define STDIN 1 
#define MAX_CMD_LENGHT 500 
#define MAX_CMD_ARGS_LENGHT 50 

extern int newDescriptor; 
extern char* fileName; 
extern int pCount; 


typedef struct commandR* Command; 
struct commandR{ 
    char payload[MAX_CMD_LENGHT]; 
    char* payloadArgv[MAX_CMD_ARGS_LENGHT]; 
    int payloadArgc; 
}; 

extern Command cmd; 

void setSigHandler(); 

void prompt(); 

void getNextCommand(); 

void parseCommand(); 


#endif 

util.c

#include<stdio.h> 
#include<unistd.h> 
#include<stdlib.h> 
#include<string.h> 
#include<signal.h> 
#include<errno.h> 
#include"util.h" 


char* fileName = NULL; 
int pCount = -1; 
int newDescriptor = -1; 
Command cmd; 

void setSigHandler(){ 
    void (*oldHandler)(); 

    oldHandler = signal(SIGINT, SIG_IGN); 
    signal(SIGTERM, oldHandler); 
} 

void prompt(){ 
    char* user = getlogin(); 
    printf("[%s]-->$", user); 
} 

void getNextCommand(){ 
    errno = 0; 
    cmd = malloc(sizeof *cmd); 
    if(cmd == NULL){ 
     char* error = strerror(errno); 
     printf("malloc:%s\n", error); 
     exit(EXIT_FAILURE); 
    } 

    fgets(cmd->payload, sizeof(cmd->payload), stdin); 

    if(cmd->payload[strlen(cmd->payload) - 1] == '\n'){ 
     cmd->payload[strlen(cmd->payload) - 1] = '\0'; 
    } 
} 

void parseCommandString(){ 
    cmd->payloadArgc = 0; 
    char* buffer = strtok(cmd->payload, " "); 
    while(buffer != NULL){ 
     cmd->payloadArgv[cmd->payloadArgc] = buffer; 
     if(!strcmp(cmd->payloadArgv[cmd->payloadArgc], ">")){ 
      cmd->payloadArgv[cmd->payloadArgc] = NULL; 
      fileName = strtok(NULL, " "); 
      break; 
     } 
     if(!strcmp(cmd->payloadArgv[cmd->payloadArgc], "|")){ 
      cmd->payloadArgv[cmd->payloadArgc] = NULL; 
      pCount++; 
      break; 
     } 
     buffer = strtok(NULL, " ");  
     cmd->payloadArgc++; 
    } 
} 
+0

Показать ваш util.h. У меня есть подозрение. – SergeyA

+0

Я подозреваю, что у вас есть глобальная переменная в util.h, которая должна быть в util.c и "extern var_type var_name" в.h отсутствует – Krapow

+0

Да, те переменные, которые он сообщает, являются глобальными. Они должны быть в файле util.c? Не знал этого. – Akaitenshi

ответ

4

Проблема заключается в том, что у вас есть переменные, определенные в файле заголовка. Поэтому, когда вы компилируете каждый файл .c, они оба содержат копию этих переменных. Это приводит к ошибке компоновщика нескольких определений.

Что вам нужно сделать, это Объявление их в файле заголовка с ключевым словом extern. Это позволяет использовать переменные без определения. Затем вы определяете их в одном файле .c.

util.h:

extern char* fileName; 
extern int pCount; 
extern int newDescriptor; 
extern Command cmd; 

util.c:

char* fileName = NULL; 
int pCount = -1; 
int newDescriptor = -1; 
Command cmd; 

отметить также, что переменные инициализируются, где они определены, не там, где они объявлены.

EDIT:

Похоже, проблема в том, как вы собираете. Вы должны скомпилировать main.c и util.c в объектные файлы, а затем связать полученные объектные файлы:

gcc -Wall -Wextra -g -c main.c 
gcc -Wall -Wextra -g -c util.c 
gcc -Wall -Wextra -g -o main main.o util.o 

Кроме того, вы должны поместить декларацию parseCommandString в util.h, и вам необходимо включить sys/types.h и sys/wait.h в main.c для waitpid ,

+0

Спасибо за совет! Никогда раньше не работал с глобальными переменными из заголовка. Нужно ли это делать и для командной переменной? Если это не так? – Akaitenshi

+0

@Akaitenshi Да, вам нужно сделать это и для этого. На стороне примечание, это, как правило, неправильная практика для 'typedef' указателя. Это скрывает тот факт, что указатель используется и может привести к путанице. – dbush

+0

Я знаю, что это плохая привычка, что университет застрял на меня. По теме: я сделал изменения, но я все равно получаю ту же ошибку – Akaitenshi

Смежные вопросы