在C中创建一个简单的shell会导致链接错误

时间:2016-01-29 15:53:53

标签: c shell

我在C中创建一个简单的shell,它可以执行命令,执行stdout重定向和管道。到目前为止,我只完成了重定向部分,但出于某种原因,当我尝试编译collect2时会抛出一个错误。

我包含的util.c文件:

#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;
    }
}

我的主要档案:

/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

来自collect2的错误:

#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

造成这种情况的原因是什么?

我知道我的main.c代码有点难过。

编辑:请求的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

编辑2 :提出建议后我修改了我的代码。错误仍然存​​在。

util.h

#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++;
    }
}

util.c

/SQLSYSADMINACCOUNTS="Users"

1 个答案:

答案 0 :(得分: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;

另请注意,变量在定义它们的位置初始化,而不是在声明它们的位置。

编辑:

看起来问题就是你如何编译。您需要将main.cutil.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.hmain.c waitpid }}