1function spqr_make (opt1)
2%SPQR_MAKE compiles the SuiteSparseQR mexFunctions
3%
4% Example:
5%   spqr_make
6%
7% SuiteSparseQR relies on CHOLMOD, AMD, and COLAMD, and optionally CCOLAMD,
8% CAMD, and METIS.  Next, type
9%
10%   spqr_make
11%
12% in the MATLAB command window.  If METIS is not present in ../../metis-5.1.0,
13% then it is not used.
14%
15% To compile using Intel's Threading Building Blocks (TBB) use:
16%
17%   spqr_make ('tbb')
18%
19% TBB parallelism is not the default, since it conflicts with the multithreaded
20% BLAS (the Intel MKL are OpenMP based, for example).  This may change in
21% future versions.
22%
23% You must type the spqr_make command while in the SuiteSparseQR/MATLAB
24% directory.
25%
26% See also spqr, spqr_solve, spqr_qmult, qr, mldivide
27
28% Copyright 2008, Timothy A. Davis, http://www.suitesparse.com
29
30details = 0 ;       % 1 if details of each command are to be printed, 0 if not
31
32v = version ;
33try
34    % ispc does not appear in MATLAB 5.3
35    pc = ispc ;
36    mac = ismac ;
37catch                                                                       %#ok
38    % if ispc fails, assume we are on a Windows PC if it's not unix
39    pc = ~isunix ;
40    mac = 0 ;
41end
42
43flags = '' ;
44is64 = (~isempty (strfind (computer, '64'))) ;
45if (is64)
46    % 64-bit MATLAB
47    flags = '-largeArrayDims' ;
48end
49
50% MATLAB 8.3.0 now has a -silent option to keep 'mex' from burbling too much
51if (~verLessThan ('matlab', '8.3.0'))
52    flags = ['-silent ' flags] ;
53end
54
55include = '-DNMATRIXOPS -DNMODIFY -I. -I../../AMD/Include -I../../COLAMD/Include -I../../CHOLMOD/Include -I../Include -I../../SuiteSparse_config' ;
56
57% Determine if METIS is available
58metis_path = '../../metis-5.1.0' ;
59have_metis = exist (metis_path, 'dir') ;
60
61% Determine if TBB is to be used
62if (nargin < 1)
63    tbb = 0 ;
64elseif (nargin < 2)
65    tbb = strcmp (opt1, 'tbb') ;
66end
67
68% fix the METIS 4.0.1 rename.h file
69if (have_metis)
70    fprintf ('Compiling SuiteSparseQR with METIS for MATLAB Version %s\n', v) ;
71    include = [include ' -I' metis_path '/include'] ;
72    include = [include ' -I' metis_path '/GKlib'] ;
73    include = [include ' -I' metis_path '/libmetis'] ;
74    include = [include ' -I../../CCOLAMD/Include -I../../CAMD/Include' ] ;
75else
76    fprintf ('Compiling SuiteSparseQR without METIS on MATLAB Version %s\n', v);
77    include = ['-DNPARTITION ' include ] ;
78end
79
80%-------------------------------------------------------------------------------
81% BLAS option
82%-------------------------------------------------------------------------------
83
84% This is exceedingly ugly.  The MATLAB mex command needs to be told where to
85% find the LAPACK and BLAS libraries, which is a real portability nightmare.
86% The correct option is highly variable and depends on the MATLAB version.
87
88if (pc)
89    if (verLessThan ('matlab', '6.5'))
90        % MATLAB 6.1 and earlier: use the version supplied in CHOLMOD
91        lib = '../../CHOLMOD/MATLAB/lcc_lib/libmwlapack.lib' ;
92    elseif (verLessThan ('matlab', '7.5'))
93        % use the built-in LAPACK lib (which includes the BLAS)
94        lib = 'libmwlapack.lib' ;
95    elseif (verLessThan ('matlab', '9.5'))
96        lib = 'libmwlapack.lib libmwblas.lib' ;
97    else
98        lib = '-lmwlapack -lmwblas' ;
99    end
100else
101    if (verLessThan ('matlab', '7.5'))
102        % MATLAB 7.5 and earlier, use the LAPACK lib (including the BLAS)
103        lib = '-lmwlapack' ;
104    else
105        % MATLAB 7.6 requires the -lmwblas option; earlier versions do not
106        lib = '-lmwlapack -lmwblas' ;
107    end
108end
109
110if (is64 && ~verLessThan ('matlab', '7.8'))
111    % versions 7.8 and later on 64-bit platforms use a 64-bit BLAS
112    fprintf ('with 64-bit BLAS\n') ;
113    flags = [flags ' -DBLAS64'] ;
114end
115
116%-------------------------------------------------------------------------------
117% GPU option
118%-------------------------------------------------------------------------------
119
120% GPU not yet supported for the spqr MATLAB mexFunction
121% flags = [flags ' -DGPU_BLAS'] ;
122
123%-------------------------------------------------------------------------------
124% TBB option
125%-------------------------------------------------------------------------------
126
127% You should install TBB properly so that mex can find the library files and
128% include files, but you can also modify the tbb_lib_path and tbb_include_path
129% strings below to if you need to specify the path to your own installation of
130% TBB.
131
132% vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
133% >>>>>>>>>>>>>>>>>>>>> EDIT THE tbb_path BELOW AS NEEDED <<<<<<<<<<<<<<<<<<<<<<
134if (pc)
135    % For Windows, with TBB installed in C:\TBB.  Edit this line as needed:
136    tbb_path = 'C:\TBB\tbb21_009oss' ;
137else
138    % For Linux, edit this line as needed (not needed if already in /usr/lib):
139    tbb_path = '' ;
140end
141% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
142
143% You should not have to edit the lines below.
144if (pc)
145    if (is64)
146        tbb_lib_path = [tbb_path '\ia32\vc9\lib\'] ;
147    else
148        tbb_lib_path = [tbb_path '\em64t\vc9\lib\'] ;
149    end
150    tbb_include_path = [tbb_path '\include\'] ;
151else
152    % For Linux, with TBB might be already installed in /usr/lib
153    if (exist ('/usr/lib/libtbb.so', 'file'))
154        % do not edit these lines
155        tbb_path = '' ;
156        tbb_lib_path = '' ;
157        tbb_include_path = '' ;
158    else
159        if (is64)
160            tbb_lib_path = '/em64t/cc4.1.0_libc2.4_kernel2.6.16.21/lib' ;
161        else
162            tbb_lib_path = '/ia32/cc4.1.0_libc2.4_kernel2.6.16.21/lib' ;
163        end
164        tbb_lib_path = [tbb_path tbb_lib_path] ;
165        tbb_include_path = [tbb_path '/include/'] ;
166    end
167end
168
169if (tbb)
170    fprintf ('Compiling with Intel TBB parallelism\n') ;
171    lib = [lib ' -L' tbb_lib_path ' -ltbb'] ;
172    include = [include ' -I' tbb_include_path ' -DHAVE_TBB' ] ;
173end
174
175if (~(pc || mac))
176    % for POSIX timing routine
177    lib = [lib ' -lrt'] ;
178end
179
180%-------------------------------------------------------------------------------
181% ready to compile ...
182%-------------------------------------------------------------------------------
183
184config_src = { '../../SuiteSparse_config/SuiteSparse_config' } ;
185
186amd_c_src = { ...
187    '../../AMD/Source/amd_1', ...
188    '../../AMD/Source/amd_2', ...
189    '../../AMD/Source/amd_aat', ...
190    '../../AMD/Source/amd_control', ...
191    '../../AMD/Source/amd_defaults', ...
192    '../../AMD/Source/amd_dump', ...
193    '../../AMD/Source/amd_global', ...
194    '../../AMD/Source/amd_info', ...
195    '../../AMD/Source/amd_order', ...
196    '../../AMD/Source/amd_postorder', ...
197    '../../AMD/Source/amd_post_tree', ...
198    '../../AMD/Source/amd_preprocess', ...
199    '../../AMD/Source/amd_valid' } ;
200
201colamd_c_src = {
202    '../../COLAMD/Source/colamd' } ;
203
204% CAMD and CCOLAMD are not needed if we don't have METIS
205camd_c_src = { ...
206    '../../CAMD/Source/camd_1', ...
207    '../../CAMD/Source/camd_2', ...
208    '../../CAMD/Source/camd_aat', ...
209    '../../CAMD/Source/camd_control', ...
210    '../../CAMD/Source/camd_defaults', ...
211    '../../CAMD/Source/camd_dump', ...
212    '../../CAMD/Source/camd_global', ...
213    '../../CAMD/Source/camd_info', ...
214    '../../CAMD/Source/camd_order', ...
215    '../../CAMD/Source/camd_postorder', ...
216    '../../CAMD/Source/camd_preprocess', ...
217    '../../CAMD/Source/camd_valid' } ;
218
219ccolamd_c_src = {
220    '../../CCOLAMD/Source/ccolamd' } ;
221
222if (have_metis)
223
224    metis_c_src = {
225        'GKlib/b64', ...
226        'GKlib/blas', ...
227        'GKlib/csr', ...
228        'GKlib/error', ...
229        'GKlib/evaluate', ...
230        'GKlib/fkvkselect', ...
231        'GKlib/fs', ...
232        'GKlib/getopt', ...
233        'GKlib/gkregex', ...
234        'GKlib/graph', ...
235        'GKlib/htable', ...
236        'GKlib/io', ...
237        'GKlib/itemsets', ...
238        'GKlib/mcore', ...
239        'GKlib/memory', ...
240        'GKlib/omp', ...
241        'GKlib/pdb', ...
242        'GKlib/pqueue', ...
243        'GKlib/random', ...
244        'GKlib/rw', ...
245        'GKlib/seq', ...
246        'GKlib/sort', ...
247        'GKlib/string', ...
248        'GKlib/timers', ...
249        'GKlib/tokenizer', ...
250        'GKlib/util', ...
251        'libmetis/auxapi', ...
252        'libmetis/balance', ...
253        'libmetis/bucketsort', ...
254        'libmetis/checkgraph', ...
255        'libmetis/coarsen', ...
256        'libmetis/compress', ...
257        'libmetis/contig', ...
258        'libmetis/debug', ...
259        'libmetis/fm', ...
260        'libmetis/fortran', ...
261        'libmetis/frename', ...
262        'libmetis/gklib', ...
263        'libmetis/graph', ...
264        'libmetis/initpart', ...
265        'libmetis/kmetis', ...
266        'libmetis/kwayfm', ...
267        'libmetis/kwayrefine', ...
268        'libmetis/mcutil', ...
269        'libmetis/mesh', ...
270        'libmetis/meshpart', ...
271        'libmetis/minconn', ...
272        'libmetis/mincover', ...
273        'libmetis/mmd', ...
274        'libmetis/ometis', ...
275        'libmetis/options', ...
276        'libmetis/parmetis', ...
277        'libmetis/pmetis', ...
278        'libmetis/refine', ...
279        'libmetis/separator', ...
280        'libmetis/sfm', ...
281        'libmetis/srefine', ...
282        'libmetis/stat', ...
283        'libmetis/timing', ...
284        'libmetis/util', ...
285        'libmetis/wspace', ...
286    } ;
287
288    for i = 1:length (metis_c_src)
289        metis_c_src {i} = [metis_path '/' metis_c_src{i}] ;
290    end
291end
292
293cholmod_c_src = {
294    '../../CHOLMOD/Core/cholmod_aat', ...
295    '../../CHOLMOD/Core/cholmod_add', ...
296    '../../CHOLMOD/Core/cholmod_band', ...
297    '../../CHOLMOD/Core/cholmod_change_factor', ...
298    '../../CHOLMOD/Core/cholmod_common', ...
299    '../../CHOLMOD/Core/cholmod_complex', ...
300    '../../CHOLMOD/Core/cholmod_copy', ...
301    '../../CHOLMOD/Core/cholmod_dense', ...
302    '../../CHOLMOD/Core/cholmod_error', ...
303    '../../CHOLMOD/Core/cholmod_factor', ...
304    '../../CHOLMOD/Core/cholmod_memory', ...
305    '../../CHOLMOD/Core/cholmod_sparse', ...
306    '../../CHOLMOD/Core/cholmod_transpose', ...
307    '../../CHOLMOD/Core/cholmod_triplet', ...
308    '../../CHOLMOD/Check/cholmod_check', ...
309    '../../CHOLMOD/Check/cholmod_read', ...
310    '../../CHOLMOD/Check/cholmod_write', ...
311    '../../CHOLMOD/Cholesky/cholmod_amd', ...
312    '../../CHOLMOD/Cholesky/cholmod_analyze', ...
313    '../../CHOLMOD/Cholesky/cholmod_colamd', ...
314    '../../CHOLMOD/Cholesky/cholmod_etree', ...
315    '../../CHOLMOD/Cholesky/cholmod_factorize', ...
316    '../../CHOLMOD/Cholesky/cholmod_postorder', ...
317    '../../CHOLMOD/Cholesky/cholmod_rcond', ...
318    '../../CHOLMOD/Cholesky/cholmod_resymbol', ...
319    '../../CHOLMOD/Cholesky/cholmod_rowcolcounts', ...
320    '../../CHOLMOD/Cholesky/cholmod_rowfac', ...
321    '../../CHOLMOD/Cholesky/cholmod_solve', ...
322    '../../CHOLMOD/Cholesky/cholmod_spsolve', ...
323    '../../CHOLMOD/Supernodal/cholmod_super_numeric', ...
324    '../../CHOLMOD/Supernodal/cholmod_super_solve', ...
325    '../../CHOLMOD/Supernodal/cholmod_super_symbolic' } ;
326
327cholmod_c_partition_src = {
328    '../../CHOLMOD/Partition/cholmod_ccolamd', ...
329    '../../CHOLMOD/Partition/cholmod_csymamd', ...
330    '../../CHOLMOD/Partition/cholmod_camd', ...
331    '../../CHOLMOD/Partition/cholmod_metis', ...
332    '../../CHOLMOD/Partition/cholmod_nesdis' } ;
333
334% SuiteSparseQR does not need the MatrixOps or Modify modules of CHOLMOD
335%   cholmod_unused = {
336%       '../../CHOLMOD/MatrixOps/cholmod_drop', ...
337%       '../../CHOLMOD/MatrixOps/cholmod_horzcat', ...
338%       '../../CHOLMOD/MatrixOps/cholmod_norm', ...
339%       '../../CHOLMOD/MatrixOps/cholmod_scale', ...
340%       '../../CHOLMOD/MatrixOps/cholmod_sdmult', ...
341%       '../../CHOLMOD/MatrixOps/cholmod_ssmult', ...
342%       '../../CHOLMOD/MatrixOps/cholmod_submatrix', ...
343%       '../../CHOLMOD/MatrixOps/cholmod_vertcat', ...
344%       '../../CHOLMOD/MatrixOps/cholmod_symmetry', ...
345%       '../../CHOLMOD/Modify/cholmod_rowadd', ...
346%       '../../CHOLMOD/Modify/cholmod_rowdel', ...
347%       '../../CHOLMOD/Modify/cholmod_updown' } ;
348
349% SuiteSparseQR source code, and mex support file
350spqr_cpp_src = {
351    '../Source/spqr_parallel', ...
352    '../Source/spqr_1colamd', ...
353    '../Source/spqr_1factor', ...
354    '../Source/spqr_1fixed', ...
355    '../Source/spqr_analyze', ...
356    '../Source/spqr_append', ...
357    '../Source/spqr_assemble', ...
358    '../Source/spqr_cpack', ...
359    '../Source/spqr_csize', ...
360    '../Source/spqr_cumsum', ...
361    '../Source/spqr_debug', ...
362    '../Source/spqr_factorize', ...
363    '../Source/spqr_fcsize', ...
364    '../Source/spqr_freefac', ...
365    '../Source/spqr_freenum', ...
366    '../Source/spqr_freesym', ...
367    '../Source/spqr_front', ...
368    '../Source/spqr_fsize', ...
369    '../Source/spqr_happly', ...
370    '../Source/spqr_happly_work', ...
371    '../Source/spqr_hpinv', ...
372    '../Source/spqr_kernel', ...
373    '../Source/spqr_larftb', ...
374    '../Source/spqr_panel', ...
375    '../Source/spqr_rconvert', ...
376    '../Source/spqr_rcount', ...
377    '../Source/spqr_rhpack', ...
378    '../Source/spqr_rmap', ...
379    '../Source/spqr_rsolve', ...
380    '../Source/spqr_shift', ...
381    '../Source/spqr_stranspose1', ...
382    '../Source/spqr_stranspose2', ...
383    '../Source/spqr_trapezoidal', ...
384    '../Source/spqr_type', ...
385    '../Source/spqr_tol', ...
386    '../Source/spqr_maxcolnorm', ...
387    '../Source/SuiteSparseQR_qmult', ...
388    '../Source/SuiteSparseQR', ...
389    '../Source/SuiteSparseQR_expert', ...
390    '../MATLAB/spqr_mx' } ;
391
392% SuiteSparse C source code, for MATLAB error handling
393spqr_c_mx_src = { '../MATLAB/spqr_mx_error' } ;
394
395% SuiteSparseQR mexFunctions
396spqr_mex_cpp_src = { 'spqr', 'spqr_qmult', 'spqr_solve', 'spqr_singletons' } ;
397
398if (pc)
399    % Windows does not have drand48 and srand48, required by METIS.  Use
400    % drand48 and srand48 in CHOLMOD/MATLAB/Windows/rand48.c instead.
401    % Also provide Windows with an empty <strings.h> include file.
402    obj_extension = '.obj' ;
403    cholmod_c_src = [cholmod_c_src {'../../CHOLMOD/MATLAB/Windows/rand48'}] ;
404    include = [include ' -I../../CHOLMOD/MATLAB/Windows'] ;
405else
406    obj_extension = '.o' ;
407end
408
409% compile each library source file
410obj = '' ;
411
412c_source = [config_src amd_c_src colamd_c_src cholmod_c_src spqr_c_mx_src ] ;
413if (have_metis)
414    c_source = [c_source cholmod_c_partition_src ccolamd_c_src ] ;
415    c_source = [c_source camd_c_src metis_c_src] ;
416end
417
418cpp_source = spqr_cpp_src ;
419
420kk = 0 ;
421
422for f = cpp_source
423    ff = f {1} ;
424    slash = strfind (ff, '/') ;
425    if (isempty (slash))
426        slash = 1 ;
427    else
428        slash = slash (end) + 1 ;
429    end
430    o = ff (slash:end) ;
431    obj = [obj  ' ' o obj_extension] ;                                      %#ok
432    s = sprintf ('mex %s -O %s -c %s.cpp', flags, include, ff) ;
433    kk = do_cmd (s, kk, details) ;
434end
435
436for f = c_source
437    ff = f {1} ;
438    if (isequal (ff, [metis_path '/GKlib/util']))
439        % special case, since a file with the same name also exists in libmetis
440        copyfile ([ff '.c'], 'GKlib_util.c', 'f') ;
441        ff = 'GKlib_util' ;
442        o = 'GKlib_util' ;
443    elseif (isequal (ff, [metis_path '/GKlib/graph']))
444        % special case, since a file with the same name also exist in libmetis
445        copyfile ([ff '.c'], 'GKlib_graph.c', 'f') ;
446        ff = 'GKlib_graph' ;
447        o = 'GKlib_graph' ;
448    else
449        slash = strfind (ff, '/') ;
450        if (isempty (slash))
451            slash = 1 ;
452        else
453            slash = slash (end) + 1 ;
454        end
455        o = ff (slash:end) ;
456    end
457    % fprintf ('%s\n', o) ;
458    o = [o obj_extension] ;
459    obj = [obj  ' ' o] ;					            %#ok
460    s = sprintf ('mex %s -DDLONG -O %s -c %s.c', flags, include, ff) ;
461    kk = do_cmd (s, kk, details) ;
462end
463
464
465% compile each mexFunction
466for f = spqr_mex_cpp_src
467    s = sprintf ('mex %s -O %s %s.cpp', flags, include, f{1}) ;
468    s = [s obj ' ' lib] ;                                                   %#ok
469    kk = do_cmd (s, kk, details) ;
470end
471
472% clean up
473s = ['delete ' obj] ;
474status = warning ('off', 'MATLAB:DELETE:FileNotFound') ;
475delete rename.h
476warning (status) ;
477do_cmd (s, kk, details) ;
478fprintf ('\nSuiteSparseQR successfully compiled\n') ;
479
480% remove the renamed METIS files, if they exist
481if (exist ('GKlib_util.c', 'file'))
482    delete ('GKlib_util.c') ;
483end
484if (exist ('GKlib_graph.c', 'file'))
485    delete ('GKlib_graph.c') ;
486end
487
488%-------------------------------------------------------------------------------
489function kk = do_cmd (s, kk, details)
490%DO_CMD evaluate a command, and either print it or print a "."
491if (details)
492    fprintf ('%s\n', s) ;
493else
494    if (mod (kk, 60) == 0)
495        fprintf ('\n') ;
496    end
497    kk = kk + 1 ;
498    fprintf ('.') ;
499end
500eval (s) ;
501
502