1/* Call Windows NT 3.x linker. 2 Copyright (C) 1994, 1995 Free Software Foundation, Inc. 3 Contributed by Douglas B. Rupp (drupp@cs.washington.edu). 4 5This file is part of GNU CC. 6 7GNU CC is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2, or (at your option) 10any later version. 11 12GNU CC is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GNU CC; see the file COPYING. If not, write to 19the Free Software Foundation, 59 Temple Place - Suite 330, 20Boston, MA 02111-1307, USA. */ 21 22#include "config.h" 23#include <stdio.h> 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <stdlib.h> 27#include <string.h> 28#include <process.h> 29 30static char *concat (); 31static char *concat3 (); 32 33/* These can be set by command line arguments */ 34char *linker_path = 0; 35int verbose = 0; 36int subsystem = 0; 37int entry = 0; 38 39int link_arg_max = -1; 40char **link_args = (char **) 0; 41int link_arg_index = -1; 42 43char *search_dirs = "."; 44 45static int is_regular_file (char *name); 46 47/* Add the argument contained in STR to the list of arguments to pass to the 48 linker */ 49 50static void 51addarg (str) 52 char *str; 53{ 54 int i; 55 56 if (++link_arg_index >= link_arg_max) 57 { 58 char **new_link_args 59 = (char **) calloc (link_arg_max + 1000, sizeof (char *)); 60 61 for (i = 0; i <= link_arg_max; i++) 62 new_link_args [i] = link_args [i]; 63 64 if (link_args) 65 free (link_args); 66 67 link_arg_max += 1000; 68 link_args = new_link_args; 69 } 70 71 link_args [link_arg_index] = str; 72} 73 74/* Locate the file named in FILE_NAME in the set of paths contained in 75 PATH_VAL */ 76 77static char * 78locate_file (file_name, path_val) 79 char *file_name; 80 char *path_val; 81{ 82 char buf [1000]; 83 int file_len = strlen (file_name); 84 char *end_path = path_val + strlen (path_val); 85 char *ptr; 86 87 /* Handle absolute pathnames */ 88 if (file_name [0] == '/' || file_name [0] == DIR_SEPARATOR 89 || isalpha (file_name [0]) && file_name [1] == ':') 90 { 91 strncpy (buf, file_name, sizeof buf); 92 buf[sizeof buf - 1] = '\0'; 93 if (is_regular_file (buf)) 94 return strdup (buf); 95 else 96 return 0; 97 } 98 99 if (! path_val) 100 return 0; 101 102 for (;;) 103 { 104 for (; *path_val == PATH_SEPARATOR ; path_val++) 105 ; 106 if (! *path_val) 107 return 0; 108 109 for (ptr = buf; *path_val && *path_val != PATH_SEPARATOR; ) 110 *ptr++ = *path_val++; 111 112 ptr--; 113 if (*ptr != '/' && *ptr != DIR_SEPARATOR) 114 *++ptr = DIR_SEPARATOR; 115 116 strcpy (++ptr, file_name); 117 118 if (is_regular_file (buf)) 119 return strdup (buf); 120 } 121 122 return 0; 123} 124 125/* Given a library name in NAME, i.e. foo. Look first for libfoo.lib and then 126 libfoo.a in the set of directories we are allowed to search in */ 127 128static char * 129expand_lib (name) 130 char *name; 131{ 132 char *lib, *lib_path; 133 134 lib = malloc (strlen (name) + 8); 135 strcpy (lib, "lib"); 136 strcat (lib, name); 137 strcat (lib, ".lib"); 138 lib_path = locate_file (lib, search_dirs); 139 if (!lib_path) 140 { 141 strcpy (lib, "lib"); 142 strcat (lib, name); 143 strcat (lib, ".a"); 144 lib_path = locate_file (lib, search_dirs); 145 if (!lib_path) 146 { 147 fprintf 148 (stderr, 149 "Couldn't locate library: lib%s.a or lib%s.lib\n", name, name); 150 exit (1); 151 } 152 } 153 154 return lib_path; 155} 156 157/* Check to see if the file named in NAME is a regular file, i.e. not a 158 directory */ 159 160static int 161is_regular_file (name) 162 char *name; 163{ 164 int ret; 165 struct stat statbuf; 166 167 ret = stat(name, &statbuf); 168 return !ret && S_ISREG (statbuf.st_mode); 169} 170 171/* Process the number of args in P_ARGC and contained in ARGV. Look for 172 special flags, etc. that must be handled for the Microsoft linker */ 173 174static void 175process_args (p_argc, argv) 176 int *p_argc; 177 char *argv[]; 178{ 179 int i, j; 180 181 for (i = 1; i < *p_argc; i++) 182 { 183 /* -v turns on verbose option here and is passed on to gcc */ 184 if (! strcmp (argv [i], "-v")) 185 verbose = 1; 186 else if (! strncmp (argv [i], "-g", 2)) 187 { 188 addarg ("-debugtype:coff -debug:full"); 189 } 190 else if (! strncmp (argv [i], "-stack", 6)) 191 { 192 i++; 193 addarg (concat ("-stack:",argv[i])); 194 } 195 else if (! strncmp (argv [i], "-subsystem", 10)) 196 { 197 subsystem = 1; 198 i++; 199 addarg (concat ("-subsystem:",argv[i])); 200 } 201 else if (! strncmp (argv [i], "-e", 2)) 202 { 203 entry = 1; 204 i++; 205 addarg (concat ("-entry:",&argv[i][1])); 206 } 207 } 208} 209 210/* The main program. Spawn the Microsoft linker after fixing up the 211 Unix-like flags and args to be what the Microsoft linker wants */ 212 213main (argc, argv) 214 int argc; 215 char *argv[]; 216{ 217 int i; 218 int done_an_ali = 0; 219 int file_name_index; 220 char *pathval = getenv ("PATH"); 221 char *spawn_args [5]; 222 char *tmppathval = malloc (strlen (pathval) + 3); 223 224 strcpy (tmppathval, ".;"); 225 pathval = strcat (tmppathval, pathval); 226 227 linker_path = locate_file ("link32.exe", pathval); 228 if (!linker_path) 229 { 230 linker_path = locate_file ("link.exe", pathval); 231 if (!linker_path) 232 { 233 fprintf (stderr, "Couldn't locate link32 or link\n"); 234 exit (1); 235 } 236 } 237 238 addarg (linker_path); 239 240 process_args (&argc , argv); 241 if (! subsystem) addarg ("-subsystem:console"); 242 if (! entry) addarg ("-entry:mainCRTStartup"); 243 244 for (i = 1; i < argc; i++) 245 { 246 int arg_len = strlen (argv [i]); 247 248 if (!strcmp (argv [i], "-o")) 249 { 250 char *buff, *ptr; 251 int out_len; 252 253 i++; 254 out_len = strlen (argv[i]) + 10; 255 buff = malloc (out_len); 256 strcpy (buff, "-out:"); 257 strcat (buff, argv[i]); 258 ptr = strstr (buff, ".exe"); 259 if (ptr == NULL || strlen (ptr) != 4) 260 strcat (buff, ".exe"); 261 addarg (buff); 262 } 263 else if (arg_len > 2 && !strncmp (argv [i], "-L", 2)) 264 { 265 char *nbuff, *sdbuff; 266 int j, new_len, search_dirs_len; 267 268 new_len = strlen (&argv[i][2]); 269 search_dirs_len = strlen (search_dirs); 270 271 nbuff = malloc (new_len + 1); 272 strcpy (nbuff, &argv[i][2]); 273 274 for (j = 0; j < new_len; j++) 275 if (nbuff[j] == '/') nbuff[j] = DIR_SEPARATOR; 276 277 sdbuff = malloc (search_dirs_len + new_len + 2); 278 strcpy (sdbuff, search_dirs); 279 sdbuff[search_dirs_len] = PATH_SEPARATOR; 280 sdbuff[search_dirs_len+1] = 0; 281 strcat (sdbuff, nbuff); 282 283 search_dirs = sdbuff; 284 } 285 286 else if (arg_len > 2 && !strncmp (argv [i], "-l", 2)) 287 { 288 addarg (expand_lib (&argv[i][2])); 289 } 290 else if (!strcmp (argv [i], "-v") 291 || !strcmp (argv [i], "-g") 292 || !strcmp (argv [i], "-noinhibit-exec")) 293 { 294 ; 295 } 296 else if (!strcmp (argv [i], "-stack") 297 || !strcmp (argv [i], "-subsystem") 298 || !strcmp (argv [i], "-e")) 299 { 300 i++; 301 } 302 else 303 { 304 addarg (argv [i]); 305 } 306 } 307 308 addarg (NULL); 309 310 if (verbose) 311 { 312 int i; 313 314 for (i = 0; i < link_arg_index; i++) 315 printf ("%s ", link_args [i]); 316 putchar ('\n'); 317 } 318 319 if (spawnvp (P_WAIT, linker_path, (const char * const *)link_args) != 0) 320 { 321 fprintf (stderr, "Error executing %s\n", link_args[0]); 322 exit (1); 323 } 324 325 exit (0); 326} 327 328static char * 329concat (s1, s2) 330 char *s1, *s2; 331{ 332 int len1 = strlen (s1); 333 int len2 = strlen (s2); 334 char *result = malloc (len1 + len2 + 1); 335 336 strcpy (result, s1); 337 strcpy (result + len1, s2); 338 *(result + len1 + len2) = 0; 339 340 return result; 341} 342 343static char * 344concat3 (s1, s2, s3) 345 char *s1, *s2, *s3; 346{ 347 return concat (concat (s1, s2), s3); 348} 349