views:

108

answers:

1

I've been trying to compile a program for hardlinking duplicate files called freedup. I did try to email the author/maintainer of the program, but it's been a long time and I haven't heard anything back from him.

I'm trying to compile the program from a cygwin environment using the latest stable versions of gcc (3.4.4-999) and make (3.81-2). I've tried deleting all the object files and running make, but I always get the following error:

freedup.o: In function 'main':
/home/[user]/freedup-1.5/freedup.c:1791: undefined reference to '_hashed'
collect2: ld returned 1 exit status make: * * * [freedup] Error 1

I did take a look at the source code and saw that the "hashed" function is an inline function (which I didn't think had to be declared outside of the source file... but that's just what I gathered from some preliminary googling).

If anyone would be kind enough to try compiling this program in a windows environment and has any luck, I'd really appreciate it. Thanks

The direct link for the source files is: http://freedup.org/freedup-1.5-3-src.tgz

+1  A: 

I'm not impressed by code that uses '#include <linux/stat.h>' instead of '#include <sys/stat.h>'. I'm also unimpressed by code where the version.h file contains:

-e #define VERSION "1.5-3"

(That file is generated by a command - 'echo -e '#define...' > version.h'. Ugh!)

If you change the function from:

inline int hashed(const char*s)
{
    int returnval=atoi(s);

    if(returnval>2) returnval=2;
    if(returnval<0) returnval=0;
    return returnval;
}

to:

static
inline int hashed(const char*s)
{
    int returnval=atoi(s);

    if(returnval>2) returnval=2;
    if(returnval<0) returnval=0;
    return returnval;
}

(and fix the other problems alluded to above), then it compiles on MacOS X 10.6.2 with GCC "i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) (dot 1)".

The test code fails at random points since it assumes the touch in /bin/touch (it is /usr/bin/touch on MacOS X). There are also many warnings about 'type qualifiers ignored on function return type' because 'auto.h' defines 4 functions as returning 'const int' (for various guises of 'int'), and also in function pointers in a structure in the same header.

I guess this comes down to insufficient experience on the part of the authors - or insufficient platforms tested. The version.h command does not need to use a tab (I believe the '-e' is to expand the '\t' notation in the command line - the Makefile should be fixed to omit the '-e' and replace the '\t' with a simple blank.

The behaviour of 'inline' in standard C99 is interesting:

6.7.4 Function specifiers

Syntax

function-specifier:

    inline

Constraints

Function specifiers shall be used only in the declaration of an identifier for a function.

An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static storage duration, and shall not contain a reference to an identifier with internal linkage.

In a hosted environment, the inline function specifier shall not appear in a declaration of main.

Semantics

A function declared with an inline function specifier is an inline function. The function specifier may appear more than once; the behavior is the same as if it appeared only once. Making a function an inline function suggests that calls to the function be as fast as possible.118) The extent to which such suggestions are effective is implementation-defined.119)

Any function with internal linkage can be an inline function. For a function with external linkage, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit. If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.120)

118) By using, for example, an alternative to the usual function call mechanism, such as ‘‘inline substitution’’. Inline substitution is not textual substitution, nor does it create a new function. Therefore, for example, the expansion of a macro used within the body of the function uses the definition it had at the point the function body appears, and not where the function is called; and identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a single address, regardless of the number of inline definitions that occur in addition to the external definition.

119) For example, an implementation might never perform inline substitution, or might only perform inline substitutions to calls in the scope of an inline declaration.

120) Since an inline definition is distinct from the corresponding external definition and from any other corresponding inline definitions in other translation units, all corresponding objects with static storage duration are also distinct in each of the definitions.

Jonathan Leffler
correct on all counts. Inline functions are tricky. If you compile without optimization, and the compiler doesn't inline your function, then you will get a link error if you don't put extern inline foo(); in one .c file to force a non-inline definition to be emitted there.
Peter Cordes