我在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"
答案 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.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
}}