libtool-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static take 2


From: Charles Wilson
Subject: Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static take 2
Date: Mon, 05 Jan 2009 09:08:42 -0500
User-agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.19) Gecko/20081209 Thunderbird/2.0.0.19 Mnenhy/0.7.5.666

Peter Rosin wrote:
> Den 2009-01-05 06:24 skrev Charles Wilson:
> Interesting! Meanwhile, I have done some experiments on my own, as I
> don't like the dependence on anything that comes with MinGW when
> dealing with libtool and MSVC.

I kind of suspected that. What about the attached?  This version needs
to link against libbfd and its dependencies -- so has to be compiled
using mingw gcc.  But if this executable was included as part of msys?

> (Speaking of dependencies, I don't think the current MinGW code
>  in libtool requires 'file' to be present, and I don't think it is
>  part of a minimal MSYS install. It's not in my install anyway.)

Only because its been over two years since "msys 1.11 will be ready
RSN". It is intended that the file package be included in the minimal
1.11 install.

> I have found that for MSVC import libraries the simplest thing is
> to list the archive members to get to the dll name. I have tried
> with:
>   lib -nologo -list $implib | grep -v '\.obj$' | sort -u
> or, in gnu speak:
>   ar t $implib | grep -v '\.obj$' | sort -u

I noticed that, but wasn't sure if self-compiled (using MSVC) import
libraries were the same.

> This works for all troublesome implibs that you have listed above
> (at least those that I have easy access to, but I have at least one
> from each class of problems) and a few others. Except for MAPI.lib,
> but my MS provided dumpbin.exe (VS 2005) says
>   MAPI.lib : warning LNK4048: Invalid format file; ignored
> for that one so I too think it is a pathological case.

Ack.

> Also, it will not fail for Vfw32.Lib, it will instead list the three
> dlls it imports (AVICAP32.dll, AVIFIL32.dll, MSVFW32.dll).

Well, we probably want it to fail. dlpreopen is supposed to work like
dlopen -- and you'd need to dlopen each of the three DLLs separately.
But if you -dlpreopen Vfw32.Lib, you'd need to determine which symbols
IN Vfw32.Lib came from which DLL, and generate three different groups in
you LT_LTX_*[] structure, to register those symbols with their effective
"dlopen" source:
   { "AVICAP32.dll", 0 }
   { .... symbols .... }
   { "AVIFIL32.dll", 0 }
   { .... symbols .... }
   { "MSVFW32.dll", 0 }
   { .... symbols .... }
I don't think this is going to work well.

> Using MS tools (instead of file or objdump -f) to identify if a .lib
> is an import lib or a static lib seems to be trickier. One thing
> that appears to work is to look for an __IMPORT_DESCRIPTOR_* symbol,
> but that can obviously be thwarted by a devious (or ignorant) user...

That's ok. Rule #486: don't deliberately try to undermine your tools,
and then expect them to work.

> BTW, those symbols also identifies the imported dll (but that breaks
> when that which is imported isn't named foo.dll). E.g.
>   dumpbin -symbols $lib | grep '| __IMPORT_DESCRIPTOR_'
> 
> (output for Vfw32.Lib
>   001 00000000 SECT2  notype       External     |
> __IMPORT_DESCRIPTOR_MSVFW32
>   001 00000000 SECT2  notype       External     |
> __IMPORT_DESCRIPTOR_AVIFIL32
>   001 00000000 SECT2  notype       External     |
> __IMPORT_DESCRIPTOR_AVICAP32
> )
> 
> or, in gnu speak:
>   nm $lib | grep 'I __IMPORT_DESCRIPTOR_'
> (output for Vfw32.Lib
>   00000000 I __IMPORT_DESCRIPTOR_MSVFW32
>   00000000 I __IMPORT_DESCRIPTOR_AVIFIL32
>   00000000 I __IMPORT_DESCRIPTOR_AVICAP32
> )

Yeah, I wanted to avoid assuming that non-libtool shared libraries
always in in *.dll, because many packages (especially ones that do
dlopen/dlpreopen) still name their modules "foo.so" even on
cygwin/mingw. Take ImageMagick, for instance.

>> But...I also dislike for fixes to existing bugs, in existing platforms,
>> to be held up by not-yet-in-master support for other compilers. So, can
>> we get back to discussing the original patch, under the predicates of
>> cygwin and mingw (not msvc) $hosts?
> 
> Hey, I'm not opposed to the patch, I didn't intend to make that impression
> either, sorry if I did. I'm just trying to determine what needs to be
> done in the MSVC branch to "keep up". Just poking and asking questions,
> so thank you very much for your valuable input!

Oh, ok.  Thanks.

--
Chuck

/* dllname.c -- tool to extract the name of the DLL associated with
   an import library.
   Copyright 2008 Charles S. Wilson

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
   02110-1301, USA.  */

#include <stdio.h>
#include <stdarg.h>
#include <bfd.h>
#include <ansidecl.h>
#include <unistd.h>             /* for open(), lseek(), read() */
#include <fcntl.h>              /* for O_RDONLY, O_BINARY */
#include <errno.h>
#include <assert.h>

static const char* VERSION_STRING = "cygutils x.y.z";
static int pe_dll_extra_pe_debug = 0;

/* Can't #include getopt on cygwin, because
   it declares optarg as declspec(dllimport), but
   we will be linking against libiberty, and using
   its getopt. So, we need the non-dllimport optarg.
   Unfortunately, that also means we must declare
   pretty much everything from getopt.h ourselves.
*/
extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;
struct option
{
  const char *name;
  int has_arg;
  int *flag;
  int val;
};
#define no_argument             0
#define required_argument       1
#define optional_argument       2
extern int getopt (int argc, char *const *argv, const char *shortopts);
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
                        const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
                             const char *shortopts,
                             const struct option *longopts, int *longind);
extern const char *lbasename (const char *);
extern char *xstrdup (const char *s);
#define DMGL_PARAMS      (1 << 0)       /* Include function args */
#define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */
extern char * cplus_demangle (const char *mangled, int options);



static char *identify_dll_name = NULL;
static char *identify_imp_name = NULL;
static char *def_from_dll_dllname = NULL;
static FILE* output_def;
static char *program_name;
static char **oav;
static int no_ordinals = 0;
static int identify_ms = 0;

static void identify_dll_for_implib (void);
static void identify_search_archive (bfd*);
static void identify_search_member (bfd*, bfd*);
static void identify_search_section (bfd *, asection *, void *);
static void generate_def_from_dll (void);
static unsigned int pe_get16 (int fd, off_t offset);
static unsigned int pe_get32 (int fd, off_t offset);
static unsigned int pe_as32 (void *ptr);
static void bfd_nonfatal (const char *);
static void bfd_fatal (const char *);
static void report (const char *, va_list);
static void fatal VPARAMS ((const char *, ...));
static void non_fatal VPARAMS ((const char *, ...));


static void
usage (FILE *file, int status)
{
  fprintf (file, "Usage %s <option(s)>\n", program_name);
  fprintf (file, "   -z --output-def <file>    Name of .def file to be 
created.\n");
  fprintf (file, "   -D --def-from-dll <dll>   Extract a .def file for 
<dll>\n");
  fprintf (file, "      --no-ordinals          Don't include ordinal in .def 
file\n");
  fprintf (file, "   -I --identify <implib>    Report the name of the DLL 
associated with <implib>.\n");
  fprintf (file, "      --identify-ms          Modify the behavior of -I to 
work with MS implibs.\n");
  fprintf (file, "   -V --version              Display the program version.\n");
  fprintf (file, "   -h --help                 Display this information.\n");
  fprintf (file, "Note that --def-from-dll is rather crippled; it does not 
properly\n");
  fprintf (file, "decorate stdcall or fastcall symbols, because the necessary 
information\n");
  fprintf (file, "is not present in the DLL file itself.\n");
  exit (status);
}

void
print_version (const char *name)
{
  printf ("%s %s\n", name, VERSION_STRING);
  printf ("Copyright 2008,2009 Charles S. Wilson\n");
  printf ("\
This program is free software; you may redistribute it under the terms of\n\
the GNU General Public License version 3 or (at your option) any later 
version.\n\
This program has absolutely no warranty.\n");
  exit (0);
}


#define OPTION_NO_ORDINALS              150
#define OPTION_IDENTIFY_MS             (OPTION_NO_ORDINALS + 1)

 const struct option long_options[] =
{
  {"output-def", required_argument, NULL, 'z'},
  {"def-from-dll", required_argument, NULL, 'D'},
  {"no-ordinals", no_argument, NULL, OPTION_NO_ORDINALS},
  {"identify", required_argument, NULL, 'I'},
  {"identify-ms", no_argument, NULL, OPTION_IDENTIFY_MS},
  {"version", no_argument, NULL, 'V'},
  {"help", no_argument, NULL, 'h'},
  {NULL,0,NULL,0}
};

int main (int ac, char** av)
{
  int c;
  int i;
  char *firstarg = 0;
  program_name = av[0];
  xmalloc_set_program_name (program_name);
  oav = av;
  output_def = stdout;

  expandargv (&ac, &av);

  while ((c = getopt_long (ac, av, "z:D:HhI:V", long_options, 0)) != EOF)
    {
      switch (c)
        {
        case 'D':
          def_from_dll_dllname = optarg;
          break;
        case 'H':
        case 'h':
          usage (stdout, 0);
          break;
        case 'I':
          identify_imp_name = optarg;
          break;
        case 'V':
          print_version (program_name);
          break;
        case 'z':
          if (output_def && output_def != stdout)
            {
              fclose (output_def);
            }
          output_def = fopen (optarg, "wb");
          break;
        case OPTION_NO_ORDINALS:
          no_ordinals = 1;
          break;
        case OPTION_IDENTIFY_MS:
          identify_ms = 1;
          break;
        default:
          usage (stderr, 1);
          break;
        }
    }

  if (identify_imp_name)
    {
      identify_dll_for_implib ();
    }

  if (def_from_dll_dllname)
    {
      generate_def_from_dll ();
      if (output_def && (output_def != stdout))
        {
          fclose (output_def);
        }
    }

  return 0;
}

/* identify_dll_for_implib

   This is the main implementation for the --identify option.
   Given the name of an import library in identify_imp_name,
   search all archive members for an .idata$7 section
   (.idata$6 on PPC). This section will consist of a single
   char* constant, indicating the name of the DLL represented
   by the import library.

   It is possible to construct an import library that has
   two members with a non-empty .idata$7 section, but these
   are not often seen in normal operation.  In this case,
   an error is flagged.
*/   
static void 
identify_dll_for_implib (void)
{
  bfd* abfd = NULL;

  bfd_init ();

  abfd = bfd_openr (identify_imp_name, 0);
  if (abfd == NULL)
    {
      bfd_fatal (identify_imp_name);
    }
  if (!bfd_check_format (abfd, bfd_archive))
    {
      if (!bfd_close (abfd))
        bfd_fatal (identify_imp_name);

      fatal ("%s is not a library", identify_imp_name);
    }

  identify_search_archive (abfd);

  if (!bfd_close (abfd))
    bfd_fatal (identify_imp_name);

  if (identify_dll_name && *identify_dll_name)
    {
      printf ("%s\n",identify_dll_name);
      free (identify_dll_name);
      identify_dll_name = NULL;
    }
  else
    {
      fatal ("Unable to determine dll name for %s (not an import library?)", 
identify_imp_name);
    }
}


/* identify_search_archive

   Loop over all members of the archive, inspecting 
   each for the presence of an .idata$7 (.idata$6 on PPC)
   section with non-empty contents.
*/   
static void
identify_search_archive (bfd* abfd)
{
  bfd *arfile = NULL;
  bfd *last_arfile = NULL;
  char **matching;

  while (1)
    {
      arfile = bfd_openr_next_archived_file (abfd, arfile);

      if (arfile == NULL)
        {
          if (bfd_get_error () != bfd_error_no_more_archived_files)
            bfd_fatal (bfd_get_filename (abfd));
          break;
        }
      if (bfd_check_format_matches (arfile, bfd_object, &matching))
        {
          identify_search_member (arfile, abfd);
        }
      else
        {
          bfd_nonfatal (bfd_get_filename (arfile));
          free (matching);
        }
      if (last_arfile != NULL)
        {
          bfd_close (last_arfile);
        }
      last_arfile = arfile;
    }

  if (last_arfile != NULL)
    {
      bfd_close (last_arfile);
    }
}

/* identify_search_member

   Search all sections of an archive member for the 
   one with section name of .idata$7 (.idata$6 on PPC)
   and non-empty contents.
*/   
static void
identify_search_member (bfd* abfd, bfd* archive_bfd)
{
  bfd_map_over_sections (abfd, identify_search_section, NULL);
}

/* identify_process_section_p

   This predicate returns true if section->name
   matches the desired value. By default, this is
   .idata$7 (.idata$6 on PPC, or when --identify-ms)
*/   
static bfd_boolean
identify_process_section_p (asection * section)
{
  static const char * SECTION_NAME =
#ifdef DLLTOOL_PPC
  /* dllname is stored in idata$6 on PPC */
  ".idata$6";
#else
  ".idata$7";
#endif
  static const char * MS_SECTION_NAME = ".idata$6";

  const char * section_name =
    (identify_ms ? MS_SECTION_NAME : SECTION_NAME);

  if (strcmp (section_name, section->name) == 0)
    return TRUE;
  return FALSE;
}

/* identify_search_section

   If *section has contents and its name is .idata$7
   (.data$6 on PPC) then store the contents in 
   identify_dll_name as an xmalloc'ed array.

   However, if identify_dll_name already has
   a value, flag an error. We don't know how to handle
   import libraries that directly reference more than
   one DLL. (This is different than forwarded symbols.
   Such import libraries are not seen in normal operation,
   and must be specifically constructed.)
*/   
static void
identify_search_section (bfd *abfd, asection *section, void *dummy 
ATTRIBUTE_UNUSED)
{
  bfd_byte *data = 0;
  bfd_size_type datasize;

  if ((section->flags & SEC_HAS_CONTENTS) == 0)
    return;

  if (! identify_process_section_p (section))
    return;

  /* binutils import libs distinguish the .idata$7 section that 
     contains the  DLL name from other .idata$7 sections by
     the absence of the SEC_RELOC flag
  */
  if (!identify_ms && ((section->flags & SEC_RELOC) == SEC_RELOC))
    return;

  /* MS import libs distinguish the .idata$6 section that
     contains the  DLL name from other .idata$6 sections by
     the presence of the SEC_DATA flag */
  if (identify_ms && ((section->flags & SEC_DATA) == 0))
    return;

  if ((datasize = bfd_section_size (abfd, section)) == 0)
    return;

  data = (bfd_byte*) xmalloc (datasize + 1);
  data[0] = '\0';

  bfd_get_section_contents (abfd, section, data, 0, datasize);
  if (data[0] != '\0')
    {
      if (identify_dll_name != NULL)
        {
          if (*identify_dll_name != '\0')
            {
              /* The import library specifies two different DLLs.
                 Treat this as an error. */
              fatal ("Import library `%s' specifies two or more dlls: `%s' and 
`%s'",
                     identify_imp_name, identify_dll_name, data);
            }
          else
            {
              /* For some reason memory was allocated, but the
                 contents were empty. Free the memory and continue. */
              free (identify_dll_name);
            }
        }
      identify_dll_name = (char*) xstrdup (data);
    }

  free (data);
}


static void
generate_def_from_dll (void)
{
  int dll;
  unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
  unsigned long export_rva, export_size, nsections, secptr, expptr;
  unsigned long name_rvas, ordinals, nexp, ordbase, exp_funcbase;
  unsigned char *expdata, *erva;
  char          *dllname;
  /* Initialization with start > end guarantees that is_data
     will not be set by mistake, and avoids compiler warning.  */
  unsigned long data_start = 1;
  unsigned long data_end = 0;
  unsigned long rdata_start = 1;
  unsigned long rdata_end = 0;
  unsigned long bss_start = 1;
  unsigned long bss_end = 0;

  if (!output_def)
    {
      fatal ("Could not open file for .def output");
    }

  dll = open (def_from_dll_dllname, O_RDONLY|O_BINARY);
  if (dll < 1)
    {
      fatal ("Could not read dll `%s': %s", def_from_dll_dllname, 
strerror(errno));
    }
  


  pe_header_offset = pe_get32 (dll, 0x3c);
  opthdr_ofs = pe_header_offset + 4 + 20;
#ifdef pe_use_x86_64
  num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4); /*  & 
NumberOfRvaAndSizes.  */
#else
  num_entries = pe_get32 (dll, opthdr_ofs + 92);
#endif

  if (num_entries < 1)
    {
      return;
    }

#ifdef pe_use_x86_64
  export_rva  = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4);
  export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4);
#else
  export_rva = pe_get32 (dll, opthdr_ofs + 96);
  export_size = pe_get32 (dll, opthdr_ofs + 100);
#endif


  nsections = pe_get16 (dll, pe_header_offset + 4 +2);
  secptr = (pe_header_offset + 4 + 20 +
            pe_get16 (dll, pe_header_offset + 4 + 16));
  expptr = 0;

  /* Get the rva and size of the export section.  */
  for (i = 0; i < nsections; i++)
    {
      char sname[8];
      unsigned long secptr1 = secptr + 40 * i;
      unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
      unsigned long vsize = pe_get32 (dll, secptr1 + 16);
      unsigned long fptr = pe_get32 (dll, secptr1 + 20);
      lseek(dll, secptr1, SEEK_SET);
      read(dll, sname, 8);
      if (vaddr <= export_rva && vaddr+vsize > export_rva)
        {
          expptr = fptr + (export_rva - vaddr);
          if (export_rva + export_size > vaddr + vsize)
            {
              export_size = vsize - (export_rva - vaddr);
            }
          break;
        }
    }


  /* Scan sections and store the base and size of the
     data and bss segments in data/base_start/end.  */
  for (i = 0; i < nsections; i++)
    {
      unsigned long secptr1 = secptr + 40 * i;
      unsigned long vsize = pe_get32 (dll, secptr1 + 8);
      unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
      unsigned long flags = pe_get32 (dll, secptr1 + 36);
      char sec_name[9];

      sec_name[8] = '\0';
      lseek (dll, secptr1, SEEK_SET);
      read (dll, sec_name, 8);

      if (strcmp(sec_name,".data") == 0)
        {
          data_start = vaddr;
          data_end = vaddr + vsize;

          if (pe_dll_extra_pe_debug)
            printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n",
                    __FUNCTION__, sec_name, (unsigned long) vaddr,
                    (unsigned long) (vaddr + vsize), (unsigned long) flags);
        }
      else if (strcmp(sec_name,".rdata") == 0)
        {
          rdata_start = vaddr;
          rdata_end = vaddr + vsize;

          if (pe_dll_extra_pe_debug)
            printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n",
                    __FUNCTION__, sec_name, (unsigned long) vaddr,
                    (unsigned long) (vaddr + vsize), (unsigned long) flags);
        }
      else if (strcmp (sec_name,".bss") == 0)
        {
          bss_start = vaddr;
          bss_end = vaddr + vsize;

          if (pe_dll_extra_pe_debug)
            printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n",
                    __FUNCTION__, sec_name, (unsigned long) vaddr,
                    (unsigned long) (vaddr + vsize), (unsigned long) flags);
        }
    }

  expdata = (unsigned char*)malloc(export_size);
  lseek (dll, expptr, SEEK_SET);
  read (dll, expdata, export_size);
  erva = expdata - export_rva;

  nexp = pe_as32 (expdata+24);
  name_rvas = pe_as32 (expdata+32);
  ordinals = pe_as32 (expdata + 36);
  ordbase = pe_as32 (expdata + 16);
  exp_funcbase = pe_as32 (expdata + 28);

  /* Use internal dll name instead of filename
     to enable symbolic dll linking.  */
  dllname = xstrdup(erva + pe_as32 (expdata + 12));
  fprintf (output_def, "LIBRARY %s\n", dllname);
  fprintf (output_def, "EXPORTS\n");

  /* Iterate through the list of symbols.  */
  for (i = 0; i<nexp; i++)
    {
      /* Pointer to the names vector.  */
      unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);

      /* Pointer to the function address vector.  */
      unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4);
      int is_data = 0;

      /* Skip unwanted symbols, which are
         exported in buggy auto-import releases.  */
      if (! CONST_STRNEQ (erva + name_rva, "_nm_"))
        {
          /* is_data is true if the address is in the data, rdata or bss
             segment.  */
          is_data =
            (func_rva >= data_start && func_rva < data_end)
            || (func_rva >= rdata_start && func_rva < rdata_end)
            || (func_rva >= bss_start && func_rva < bss_end);

          if (pe_dll_extra_pe_debug)
            printf ("%s dll-name: %s sym: %s addr: 0x%lx %s\n",
                    __FUNCTION__, dllname, erva + name_rva,
                    (unsigned long) func_rva, is_data ? "(data)" : "");

          char *quote = strchr (erva + name_rva, '.') ? "\"" : "";
          char *res = cplus_demangle (erva + name_rva, DMGL_ANSI | DMGL_PARAMS);

          if (res)
            {
              fprintf (output_def,";\t%s\n", res);
              free (res);
            }

          if (no_ordinals)
            {
              fprintf (output_def, "\t%s%s%s %s\n",
                       quote,
                       erva + name_rva,
                       quote,
                       is_data ? " DATA" : "");
            }
          else
            {
              fprintf (output_def, "\t%s%s%s @ %d%s\n",
                       quote,
                       erva + name_rva,
                       quote,
                       1 + i,
                       is_data ? " DATA" : "");
            }
        }
    }
  free (dllname);
  dllname = 0;
}


static unsigned int
pe_get16 (int fd, off_t offset)
{
  unsigned char b[2];
  lseek (fd, offset, SEEK_SET);
  read (fd, b, 2);
  return b[0] + (b[1]<<8);
}

static unsigned int
pe_get32 (int fd, off_t offset)
{
  unsigned char b[4];
  lseek (fd, offset, SEEK_SET);
  read (fd, b, 4);
  return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
}
static unsigned int
pe_as32 (void *ptr)
{
  unsigned char *b = ptr;
  return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
}



static void bfd_nonfatal (const char *string)
{
  const char *errmsg = bfd_errmsg (bfd_get_error ());

  if (string)
    fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
  else
    fprintf (stderr, "%s: %s\n", program_name, errmsg);
}

static void bfd_fatal (const char *string)
{
  bfd_nonfatal (string);
  xexit (1);
}

static void report (const char * format, va_list args)
{
  fprintf (stderr, "%s: ", program_name);
  vfprintf (stderr, format, args);
  putc ('\n', stderr);
}

static void fatal VPARAMS ((const char *format, ...))
{
  VA_OPEN (args, format);
  VA_FIXEDARG (args, const char *, format);

  report (format, args);
  VA_CLOSE (args);
  xexit (1);
}

static void non_fatal VPARAMS ((const char *format, ...))
{
  VA_OPEN (args, format);
  VA_FIXEDARG (args, const char *, format);

  report (format, args);
  VA_CLOSE (args);
}



CC = gcc
LIBS = -lbfd -liberty -lintl -lz
EXEEXT=.exe
O=o

all: dllname$(EXEEXT)

dllname$(EXEEXT): dllname.$(O)
        $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)

dllname.$(O): dllname.c
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<

.PHONY: clean
clean:
        rm -f dllname.$(O) dllname$(EXEEXT)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]