Home > front end >  Multiple definition of short_options and long_options with getopt
Multiple definition of short_options and long_options with getopt

Time:11-16

I am writing my own implementation of cat and using getopt_long to parse command line arguments. I have three files: one with function headers, one with function definitions, and one with main.

Here is the header file:

#ifndef MY_CAT_FUNCS_H_
#define MY_CAT_FUNCS_H_

#include <stddef.h>
#include <getopt.h>

const char* short_options = "benst";

const struct option long_options[] = {
    {"number-nonblank", no_argument, NULL, 'b'},
    {"number", no_argument, NULL, 'n'},
    {"squeeze-blank", no_argument, NULL, 's'},
    {NULL, 0, NULL, 0}
};

int get_flags(const char* short_options, const struct option long_options[], int argc, char **argv, int* flag_b, int* flag_e, int* flag_n, int* flag_s, int* flag_t);
void flags_controller(int optind, int argc, char** argv, int flag_b, int flag_e, int flag_n, int flag_s, int flag_t);
void output(char *filename);
void flag_n_app(char *filename);

#endif //  MY_CAT_FUNCS_H_

Here is the source file:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "my_cat_funcs.h"

int get_flags(const char* short_options, const struct option long_options[], int argc, char **argv, int* flag_b, int* flag_e, int* flag_n, int* flag_s, int* flag_t) {
    
    int option_index;
    int res;

    while ((res = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
        switch (res) {
            case 'b': {
                printf("It was flag --number-nonblank\n");
                *flag_b = 1;
                break;
            }
            case 'n': {
                *flag_n = 1;
                break;
            }
            case 's': {
                printf("It was flag squeeze-blank\n");
                *flag_s = 1;
                break;
            }
            case 'e': {
                printf("It was flag e\n");
                *flag_e = 1;
                break;
            }
            case 't': {
                printf("It was flag t\n");
                *flag_t = 1;
                break;
            }

            case '?': default: {
                printf("found unknown option");
                break;
            }
        }
    }
    return optind;
}

void flags_controller(int optind, int argc, char** argv, int flag_b, int flag_e, int flag_n, int flag_s, int flag_t) {
    while (optind < argc) {
        if (flag_b   flag_e   flag_n   flag_s   flag_t == 0) {
            output(argv[optind]);
        } else {
            if (flag_n) {
                flag_n_app(argv[optind]);
                output("buffer.txt");
            }
        }
        optind  ;
    }
}

void flag_n_app(char *filename) {
    char *line_buf = NULL;
    size_t line_buf_size = 0;
    int line_count = 0;
    ssize_t line_size;
    FILE *fp = fopen(filename, "r");
    FILE *fbuf = fopen("buffer.txt", "w ");
    if (fp) {
        line_size = getline(&line_buf, &line_buf_size, fp);
        while (line_size >= 0) {
            line_count  ;
            fprintf(fbuf, "m\t", line_count);
            ssize_t i = 0;
            while(i < line_size) {
                putc(line_buf[i  ], fbuf);
            }
            line_size = getline(&line_buf, &line_buf_size, fp);
        }
        free(line_buf);
        line_buf = NULL;
        fclose(fp);
        fclose(fbuf);
    } else {
        fprintf(stderr, "Error opening file '%s'\n", filename);
    }
}

void output(char *filename) {
    char *line_buf = NULL;
    size_t line_buf_size = 0;
    int line_count = 0;
    ssize_t line_size; //ssize_t able to represent -1 for errors
    FILE *fp = fopen(filename, "r");
    if (fp) {
        line_size = getline(&line_buf, &line_buf_size, fp);
        while (line_size >= 0) {
            line_count  ;
            ssize_t i = 0;
            while(i < line_size) {
                putc(line_buf[i  ], stdout);
            }
            line_size = getline(&line_buf, &line_buf_size, fp);
        }
        free(line_buf);
        line_buf = NULL;
        fclose(fp);
    } else {
        fprintf(stderr, "Error opening file '%s'\n", filename);
    }
}

And here is the main file:

#define _GNU_SOURCE
#include "my_cat_funcs.h"

int main(int argc, char **argv) {

    int flag_b, flag_e, flag_n, flag_s, flag_t;
   
    int optind = get_flags(short_options, long_options, argc, argv, &flag_b, &flag_e, &flag_n, &flag_s, &flag_t);
    flags_controller(optind, argc, argv, flag_b, flag_e, flag_n, flag_s, flag_t);
        
  return 0;
}

I thought I included everything correctly, but I have this error:

gcc -Wall -Wextra -Werror my_cat.c my_cat_funcs.c -o my_cat
/usr/bin/ld: /tmp/ccqYSlAb.o:(.data.rel.local 0x0): multiple definition of `short_options'; /tmp/cczSyKQa.o:(.data.rel.local 0x0): first defined here
/usr/bin/ld: /tmp/ccqYSlAb.o:(.data.rel.ro.local 0x0): multiple definition of `long_options'; /tmp/cczSyKQa.o:(.data.rel.ro.local 0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:12: my_cat] Error 1

I don't understand why this is happening. After all, there are still function headers in the header file. But for them there are no mistakes. Multiple definition only for string with short flags and for structure with long flags. I don't understand how to understand from this error text where exactly the first definition occurs. Can you please tell me why this happens and how can I fix it?

CodePudding user response:

Your header file contains definitions for short_options and long_options. So when each of your .c files include it, both of them define these variables, and then when you subsequently link them you have multiple definitions.

These shouldn't be in the header at all since they're not being used in the first source file. Instead, put them in your main file.

  • Related