4f10
[build.git] / spec2make.c
1 /*
2  * Parses RPM spec file into Makefile fragment. See
3  *
4  * http://fedora.redhat.com/docs/drafts/rpm-guide-en/ch-programming-c.html
5  *
6  * Mark Huang <mlhuang@cs.princeton.edu>
7  * Copyright (C) 2006 The Trustees of Princeton University
8  *
9  * $Id$
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <libgen.h>
16 #include <errno.h>
17 #include <rpm/rpmlib.h>
18 #include <rpm/rpmts.h>
19 #include <rpm/rpmcli.h>
20 #include <rpm/rpmbuild.h>
21 #include <rpm/rpmspec.h>
22
23 /* from f10 and up, Spec is renamed rpmSpec */
24 #ifndef _RPMTYPES_H
25 #define rpmSpec Spec
26 #endif
27
28 #ifndef PATH_MAX
29 #include <linux/limits.h>
30 #endif
31
32 extern size_t strnlen(const char *s, size_t maxlen);
33
34 /* the structure describing the options we take and the defaults */
35 static struct poptOption optionsTable[] = {
36   { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
37     "Common options for all rpm modes and executables:",
38     NULL },
39
40   POPT_AUTOALIAS
41   POPT_AUTOHELP
42   POPT_TABLEEND
43 };
44
45 /* Stolen from rpm/build/spec.c:rpmspecQuery() */
46 rpmSpec
47 rpmspecGet(rpmts ts, const char * arg)
48 {
49   char * buildRoot = NULL;
50   int recursing = 0;
51   char * passPhrase = "";
52   char *cookie = NULL;
53   int anyarch = 1;
54   int force = 1;
55
56   if (parseSpec(ts, arg, "/", buildRoot, recursing, passPhrase,
57                 cookie, anyarch, force)) {
58     fprintf(stderr, "query of specfile %s failed, can't parse\n", arg);
59     return NULL;
60   }
61
62   return rpmtsSpec(ts);
63 }
64
65 int
66 main(int argc, char *argv[])
67 {
68   poptContext context;
69   rpmts ts = NULL;
70   int ec = 0;
71   rpmSpec spec;
72   struct Source *source;
73   Package pkg;
74   const char *name, *version, *release, *arch, *unused;
75   const char *package_name;
76
77   /* BEGIN: support to pull out --target from the args list */
78   int  alen, i;
79   char *target = NULL;
80   int args = 1;
81   int tlen = strlen("--target");
82
83
84   /* walk argv list looking for --target */
85   while ((args+1)<argc) {
86     if(strncmp(argv[args],"--target",tlen)==0){
87       char **dash;
88
89       /* get arch component of the --target option */
90       dash = (char**)strchr(argv[args+1],'-');
91       if (dash != NULL) *dash=NULL;
92
93       /* copy arch component of --target option to target */
94       alen = strnlen(argv[args+1],32);
95       target = (char*)malloc(alen+1);
96       if (target == NULL) return errno;
97       strncpy(target,argv[args+1],alen);
98       target[alen]='\0';
99
100       /* change argc, argv to take out the "--target xxx" */
101       for (i=args;i<argc;i++) argv[i]=argv[i+2];
102       argc-=2;
103
104       break;
105     }
106     args++;
107   }
108   argv[1]=argv[argc-2];
109   argv[2]=argv[argc-1];
110   argv[3]=0;
111   argc=3;
112   /* END: support to pull out --target from the args list */
113
114   /* Parse common options for all rpm modes and executables */
115   context = rpmcliInit(argc, argv, optionsTable);
116
117   /* Create transaction state */
118   ts = rpmtsCreate();
119
120   /* Parse spec file. The rpmcli functions don't allow you to
121    * access the Spec structure directly, so we call our own
122    * version of rpmSpecQuery() directly. */
123   spec = rpmspecGet(ts, argv[1]);
124   package_name = argv[2];
125   if (!spec) {
126     ec = 1;
127     goto done;
128   }
129
130   /* Print sources */
131   for (source = spec->sources; source; source = source->next) {
132     char fullSource[PATH_MAX];
133
134     strncpy(fullSource, source->fullSource, sizeof(fullSource));
135     printf("%s.tarballs += SOURCES/%s\n", package_name, basename(fullSource));
136     /* computes the SOURCEDIR variable by removing .tar.gz or .tar.bz2 */
137     { 
138       char *suffixes[] = {".tar.gz",".tgz",".tar.bz2", NULL};
139       char **suffix;
140       char *suffix_index;
141                   
142       for (suffix=suffixes ; *suffix ; suffix++) {
143         printf("# trying %s\n",*suffix);
144         suffix_index=strstr(fullSource,*suffix);
145         if (suffix_index) {
146           char sourcename[PATH_MAX];
147           size_t len = (size_t)(suffix_index-fullSource);
148           strncpy(sourcename,fullSource,len);
149           sourcename[len]='\0';
150           printf ("%s.source := SOURCES/%s\n",package_name,basename(sourcename));
151           printf ("%s.codebase := CODEBASES/%s\n",package_name,package_name);
152           break;
153         }
154       }
155     }
156                     
157   }
158
159   /* Get SRPM name from name of first package */ 
160   pkg = spec->packages;
161   name = version = release = NULL;
162   (void) headerNVR(pkg->header, &name, &version, &release);
163   if (name && version && release)
164     printf("%s.srpm := SRPMS/%s-%s-%s.src.rpm\n",
165            package_name, name, version, release);
166
167   /* Print non-empty packages */
168   for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
169     name = version = release = arch = NULL;
170     (void) headerNEVRA(pkg->header, &name, &unused, &version, &release, &arch);
171     if (name && version && release && arch) {
172       if (target != NULL) {
173         if (strcmp(arch,target)!=0) {
174           arch=target;
175         }
176       }
177       /* skip empty packages */
178       if (pkg->fileList) {
179         /* attach (add) rpm path to package */
180         printf("%s.rpms += RPMS/%s/%s-%s-%s.%s.rpm\n",
181                package_name, arch, name, version, release, arch);
182         /* convenience */
183         printf("%s.rpmnames += %s\n",
184                package_name, name);
185         /* attach path to rpm name */
186         printf("%s.rpm-path := RPMS/%s/%s-%s-%s.%s.rpm\n",
187                name,arch, name, version, release, arch);
188         /* attach package to rpm name for backward resolution - should be unique */
189         printf("%s.package := %s\n",
190                name,package_name);
191       }
192     }
193   }
194
195   /* export some macros to make */
196   /* note : this relies on pl-specific conventions and might be wrong */
197   { 
198     char *macros[] = { "release" , "name" , "version" , "taglevel" , NULL } ;
199     char **nav;
200     char *macro=malloc(32);
201     for (nav=macros; *nav; nav++) {
202       sprintf(macro,"%%{%s}",*nav);
203       char *value = rpmExpand(macro,NULL);
204       printf ("%s.rpm-%s := %s\n",package_name,*nav,value);
205     }
206   }
207   
208   /* export arch */
209   printf ("%s.rpm-arch := %s\n",package_name,target);
210
211   spec = freeSpec(spec);
212
213  done:
214   ts = rpmtsFree(ts);
215   context = rpmcliFini(context);
216   return ec;
217