Fantastic Mr Fox
Fantastic Mr Fox

Reputation: 33944

Visual Studio doesn't recognize GCC linker Errors in Makefile Project

We have a cross compiled visual studio Makefile project. We have already had to introduce a solution similar to this to get it to recognize compiler errors. Ie. We have introduced a Perl script to parse the output from GCC and convert it into a form that Visual studio will understand. If we declare:

int succ = thisRandomFunction(userPointer, 1, 1);

with no definition for thisRandomFunction then we will get the linker error:

1>  ./program.a(taskqueue.o): In function `TaskQueueAdd': 1> 
D:\Git\program\taskqueue.c(94,1) : undefined reference to `thisRandomFunction' 1>  
collect2: ld returned 1 exit status 1>  make: *** [program.exe] Error 1

But visual studio doesn't actually recognize this as an error. A Visual Studio C++ console program with the same problem has the linker error:

1>  TestUndefinedReference.cpp
1>TestUndefinedReference.obj : error LNK2019: unresolved external symbol "int __cdecl something(int)" (?something@@YAHH@Z) referenced in function _main
1>D:\Projects\New folder\TestUndefinedReference\Debug\TestUndefinedReference.exe : fatal error LNK1120: 1 unresolved externals

By using this converter:

sub parseLinkerError
{
    my $str = $_[0];
    my $find = "undefined reference to";
    my $replace = "error LNK2019: unresolved external symbol";
    $str =~ s/$find/$replace/g;
    return $str
} 

We can convert this:

1>  d:\Git\program/taskqueue.c:94: undefined reference to `thisRandomFunction'

into this

1>  D:/Git/eV+/program/taskqueue.c(94,1) error LNK2019: unresolved external symbol `thisRandomFunction'

But this isnt enough to trick the visual studio linker error interpreter. What are the minimum requirements for it to see a linker error? Are there any solutions that can work without directly parsing the text?

Upvotes: 5

Views: 608

Answers (2)

Mooing Duck
Mooing Duck

Reputation: 66981

According to the documentation...

The format of the output should be:

{filename (line# [, column#]) | toolname} : 
[any text] {error | warning} code####: localizable string 

Where:

  • {a | b} is a choice of either a or b.
  • [ccc] is an optional string or parameter.

For example:

C:\sourcefile.cpp(134) : error C2143: syntax error : missing ';' before '}'
LINK : fatal error LNK1104: cannot open file 'somelib.lib'


Your sample fails because it's missing a required colon

D:/Git/eV+/program/taskqueue.c(94,1) error LNK2019: unresolved external symbol `thisRandomFunction'
                                    ^

Upvotes: 1

Fantastic Mr Fox
Fantastic Mr Fox

Reputation: 33944

So it seems like adding this line is enough to do it:

taskqueue.obj : error LNK2019: unresolved external symbol "thisRandomFunction" referenced in function TaskQueueAdd

As far as i can tell the error will be detected via the following keys:

[*].obj : error LNK2019: unresolved external symbol "[*]" referenced in function [*]

Where the [*] can be anything or nothing (it doesn't even need to be the actual function).

So the following script is enough to parse it:

my $previousUsedInFunction = "";

sub parseLinkerError
{
    my $str = $_[0];
    my $find = "undefined reference to";

    #check that our string contains the undefined reference to substring. 
    if (index($str, $find) != -1) {

        #Use regular expressions to get the important filename. 
        my $filename = "";
        if ($str =~ /\\([a-zA-Z0-9_.]*)\(/) {
            $filename = $1;
            #replace whatever filename we find with the .obj equivelent. 
            $filename =~ s/\.cpp$/\.obj/g;
            $filename =~ s/\.h$/\.obj/g;
            $filename =~ s/\.c$/\.obj/g;
        }

        #Use regular expressions to find the function name. 
        my $function = "";
        if ($str =~ /\`([a-zA-Z0-9_.()]*)\'/) {
            $function = $1;
        }

        #create the final string similar to what visual studio expects. 
        my $finalStr = " " . $filename . ' : error LNK2019: unresolved external symbol "' . $function . '" referenced in function ' . $previousUsedInFunction . "\n";

        return $finalStr;

    }
    return $str;
} 

Where the string $previousUsedInFunction is generated in the main parsing loop using the following if statement (to detect if we had an in function reference) :

elsif (/\.o\): In function \`([a-zA-Z0-9_.():]*)\'/) {
    print ("$_");
    $previousUsedInFunction = $1;       
}

Upvotes: 0

Related Questions