summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qcursor_x11.cpp
blob: 8e486289aa472107195a8c9fc72c37b3996c4069 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qdebug.h>
#include <qdatastream.h>
#include <private/qcursor_p.h>
#include <private/qt_x11_p.h>
#include <private/qapplication_p.h>
#include <qbitmap.h>
#include <qcursor.h>
#include <X11/cursorfont.h>

#include <qlibrary.h>

#ifndef QT_NO_XCURSOR
#  include <X11/Xcursor/Xcursor.h>
#endif // QT_NO_XCURSOR

#ifndef QT_NO_XFIXES
#  include <X11/extensions/Xfixes.h>
#endif // QT_NO_XFIXES

#include "qx11info_x11.h"
#include <private/qpixmap_x11_p.h>

QT_BEGIN_NAMESPACE

// Define QT_USE_APPROXIMATE_CURSORS when compiling if you REALLY want to
// use the ugly X11 cursors.

/*****************************************************************************
  Internal QCursorData class
 *****************************************************************************/

QCursorData::QCursorData(Qt::CursorShape s)
    : cshape(s), bm(0), bmm(0), hx(0), hy(0), hcurs(0), pm(0), pmm(0)
{
    ref = 1;
}

QCursorData::~QCursorData()
{
    Display *dpy = X11 ? X11->display : (Display*)0;

    // Add in checking for the display too as on HP-UX
    // we seem to get a core dump as the cursor data is
    // deleted again from main() on exit...
    if (hcurs && dpy)
        XFreeCursor(dpy, hcurs);
    if (pm && dpy)
        XFreePixmap(dpy, pm);
    if (pmm && dpy)
        XFreePixmap(dpy, pmm);
    delete bm;
    delete bmm;
}

#ifndef QT_NO_CURSOR
QCursor::QCursor(Qt::HANDLE cursor)
{
    if (!QCursorData::initialized)
        QCursorData::initialize();
    d = new QCursorData(Qt::CustomCursor);
    d->hcurs = cursor;
}

#endif

QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY)
{
    if (!QCursorData::initialized)
        QCursorData::initialize();
    if (bitmap.depth() != 1 || mask.depth() != 1 || bitmap.size() != mask.size()) {
        qWarning("QCursor: Cannot create bitmap cursor; invalid bitmap(s)");
        QCursorData *c = qt_cursorTable[0];
        c->ref.ref();
        return c;
    }
    QCursorData *d = new QCursorData;
    d->ref = 1;

    extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); // qpixmap_x11.cpp
    d->bm  = new QBitmap(qt_toX11Pixmap(bitmap));
    d->bmm = new QBitmap(qt_toX11Pixmap(mask));

    d->hcurs = 0;
    d->cshape = Qt::BitmapCursor;
    d->hx = hotX >= 0 ? hotX : bitmap.width() / 2;
    d->hy = hotY >= 0 ? hotY : bitmap.height() / 2;
    d->fg.red   = 0x0000;
    d->fg.green = 0x0000;
    d->fg.blue  = 0x0000;
    d->bg.red   = 0xffff;
    d->bg.green = 0xffff;
    d->bg.blue  = 0xffff;
    return d;
}



#ifndef QT_NO_CURSOR
Qt::HANDLE QCursor::handle() const
{
    if (!QCursorData::initialized)
        QCursorData::initialize();
    if (!d->hcurs)
        d->update();
    return d->hcurs;
}
#endif

QPoint QCursor::pos()
{
    Window root;
    Window child;
    int root_x, root_y, win_x, win_y;
    uint buttons;
    Display* dpy = X11->display;
    for (int i = 0; i < ScreenCount(dpy); ++i) {
        if (XQueryPointer(dpy, QX11Info::appRootWindow(i), &root, &child, &root_x, &root_y,
                          &win_x, &win_y, &buttons))

            return QPoint(root_x, root_y);
    }
    return QPoint();
}

/*! \internal
*/
#ifndef QT_NO_CURSOR
int QCursor::x11Screen()
{
    Window root;
    Window child;
    int root_x, root_y, win_x, win_y;
    uint buttons;
    Display* dpy = X11->display;
    for (int i = 0; i < ScreenCount(dpy); ++i) {
        if (XQueryPointer(dpy, QX11Info::appRootWindow(i), &root, &child, &root_x, &root_y,
                          &win_x, &win_y, &buttons))
            return i;
    }
    return -1;
}
#endif

void QCursor::setPos(int x, int y)
{
    QPoint current, target(x, y);

    // this is copied from pos(), since we need the screen number for the correct
    // root window in the XWarpPointer call
    Window root;
    Window child;
    int root_x, root_y, win_x, win_y;
    uint buttons;
    Display* dpy = X11->display;
    int screen;
    for (screen = 0; screen < ScreenCount(dpy); ++screen) {
        if (XQueryPointer(dpy, QX11Info::appRootWindow(screen), &root, &child, &root_x, &root_y,
                          &win_x, &win_y, &buttons)) {
            current = QPoint(root_x, root_y);
            break;
        }
    }

    if (screen >= ScreenCount(dpy))
        return;

    // Need to check, since some X servers generate null mouse move
    // events, causing looping in applications which call setPos() on
    // every mouse move event.
    //
    if (current == target)
        return;

    XWarpPointer(X11->display, XNone, QX11Info::appRootWindow(screen), 0, 0, 0, 0, x, y);
}


/*!
    \internal

    Creates the cursor.
*/

void QCursorData::update()
{
    if (!QCursorData::initialized)
        QCursorData::initialize();
    if (hcurs)
        return;

    Display *dpy = X11->display;
    Window rootwin = QX11Info::appRootWindow();

    if (cshape == Qt::BitmapCursor) {
        extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); // qpixmap_x11.cpp
#ifndef QT_NO_XRENDER
        if (!pixmap.isNull() && X11->use_xrender) {
            pixmap = qt_toX11Pixmap(pixmap);
            hcurs = XRenderCreateCursor (X11->display, pixmap.x11PictureHandle(), hx, hy);
        } else
#endif
        {
            hcurs = XCreatePixmapCursor(dpy, bm->handle(), bmm->handle(), &fg, &bg, hx, hy);
        }
        return;
    }

    static const char *cursorNames[] = {
        "left_ptr",
        "up_arrow",
        "cross",
        "wait",
        "ibeam",
        "size_ver",
        "size_hor",
        "size_bdiag",
        "size_fdiag",
        "size_all",
        "blank",
        "split_v",
        "split_h",
        "pointing_hand",
        "forbidden",
        "whats_this",
        "left_ptr_watch",
        "openhand",
        "closedhand",
        "copy",
        "move",
        "link"
    };

#ifndef QT_NO_XCURSOR
    if (X11->ptrXcursorLibraryLoadCursor) {
        // special case for non-standard dnd-* cursors
        switch (cshape) {
        case Qt::DragCopyCursor:
            hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-copy");
            break;
        case Qt::DragMoveCursor:
            hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-move");
            break;
        case Qt::DragLinkCursor:
            hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-link");
            break;
        default:
            break;
        }
        if (!hcurs)
            hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]);
    }
    if (hcurs)
        return;
#endif // QT_NO_XCURSOR

    static const uchar cur_blank_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    // Non-standard X11 cursors are created from bitmaps

#ifndef QT_USE_APPROXIMATE_CURSORS
    static const uchar cur_ver_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f,
        0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xf0, 0x0f,
        0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00 };
    static const uchar mcur_ver_bits[] = {
        0x00, 0x00, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f,
        0xfc, 0x7f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xfc, 0x7f, 0xf8, 0x3f,
        0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03 };
    static const uchar cur_hor_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x30, 0x18,
        0x38, 0x38, 0xfc, 0x7f, 0xfc, 0x7f, 0x38, 0x38, 0x30, 0x18, 0x20, 0x08,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    static const uchar mcur_hor_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x60, 0x0c, 0x70, 0x1c, 0x78, 0x3c,
        0xfc, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f, 0x78, 0x3c,
        0x70, 0x1c, 0x60, 0x0c, 0x40, 0x04, 0x00, 0x00 };
    static const uchar cur_bdiag_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e,
        0x00, 0x37, 0x88, 0x23, 0xd8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0xf8, 0x00,
        0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    static const uchar mcur_bdiag_bits[] = {
        0x00, 0x00, 0xc0, 0x7f, 0x80, 0x7f, 0x00, 0x7f, 0x00, 0x7e, 0x04, 0x7f,
        0x8c, 0x7f, 0xdc, 0x77, 0xfc, 0x63, 0xfc, 0x41, 0xfc, 0x00, 0xfc, 0x01,
        0xfc, 0x03, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00 };
    static const uchar cur_fdiag_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00,
        0xf8, 0x00, 0xd8, 0x01, 0x88, 0x23, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x3c,
        0x00, 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00 };
    static const uchar mcur_fdiag_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00,
        0xfc, 0x41, 0xfc, 0x63, 0xdc, 0x77, 0x8c, 0x7f, 0x04, 0x7f, 0x00, 0x7e,
        0x00, 0x7f, 0x80, 0x7f, 0xc0, 0x7f, 0x00, 0x00 };
    static const uchar *cursor_bits16[] = {
        cur_ver_bits, mcur_ver_bits, cur_hor_bits, mcur_hor_bits,
        cur_bdiag_bits, mcur_bdiag_bits, cur_fdiag_bits, mcur_fdiag_bits,
        0, 0, cur_blank_bits, cur_blank_bits };

    static const uchar vsplit_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
        0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
        0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
        0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
        0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
        0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    static const uchar vsplitm_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
        0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
        0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
        0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
        0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
        0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
        0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
        0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    static const uchar hsplit_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
        0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
        0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
        0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
        0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
        0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    static const uchar hsplitm_bits[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
        0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
        0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
        0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
        0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
        0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    static const uchar whatsthis_bits[] = {
        0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xf0, 0x07, 0x00,
        0x09, 0x18, 0x0e, 0x00, 0x11, 0x1c, 0x0e, 0x00, 0x21, 0x1c, 0x0e, 0x00,
        0x41, 0x1c, 0x0e, 0x00, 0x81, 0x1c, 0x0e, 0x00, 0x01, 0x01, 0x07, 0x00,
        0x01, 0x82, 0x03, 0x00, 0xc1, 0xc7, 0x01, 0x00, 0x49, 0xc0, 0x01, 0x00,
        0x95, 0xc0, 0x01, 0x00, 0x93, 0xc0, 0x01, 0x00, 0x21, 0x01, 0x00, 0x00,
        0x20, 0xc1, 0x01, 0x00, 0x40, 0xc2, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00,
        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
    static const uchar whatsthism_bits[] = {
        0x01, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x07, 0xf8, 0x0f, 0x00,
        0x0f, 0xfc, 0x1f, 0x00, 0x1f, 0x3e, 0x1f, 0x00, 0x3f, 0x3e, 0x1f, 0x00,
        0x7f, 0x3e, 0x1f, 0x00, 0xff, 0x3e, 0x1f, 0x00, 0xff, 0x9d, 0x0f, 0x00,
        0xff, 0xc3, 0x07, 0x00, 0xff, 0xe7, 0x03, 0x00, 0x7f, 0xe0, 0x03, 0x00,
        0xf7, 0xe0, 0x03, 0x00, 0xf3, 0xe0, 0x03, 0x00, 0xe1, 0xe1, 0x03, 0x00,
        0xe0, 0xe1, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00,
        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
    static const uchar busy_bits[] = {
        0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
        0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
        0x41, 0xe0, 0xff, 0x00, 0x81, 0x20, 0x80, 0x00, 0x01, 0xe1, 0xff, 0x00,
        0x01, 0x42, 0x40, 0x00, 0xc1, 0x47, 0x40, 0x00, 0x49, 0x40, 0x55, 0x00,
        0x95, 0x80, 0x2a, 0x00, 0x93, 0x00, 0x15, 0x00, 0x21, 0x01, 0x0a, 0x00,
        0x20, 0x01, 0x11, 0x00, 0x40, 0x82, 0x20, 0x00, 0x40, 0x42, 0x44, 0x00,
        0x80, 0x41, 0x4a, 0x00, 0x00, 0x40, 0x55, 0x00, 0x00, 0xe0, 0xff, 0x00,
        0x00, 0x20, 0x80, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    static const uchar busym_bits[] = {
        0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
        0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
        0x7f, 0xe0, 0xff, 0x00, 0xff, 0xe0, 0xff, 0x00, 0xff, 0xe1, 0xff, 0x00,
        0xff, 0xc3, 0x7f, 0x00, 0xff, 0xc7, 0x7f, 0x00, 0x7f, 0xc0, 0x7f, 0x00,
        0xf7, 0x80, 0x3f, 0x00, 0xf3, 0x00, 0x1f, 0x00, 0xe1, 0x01, 0x0e, 0x00,
        0xe0, 0x01, 0x1f, 0x00, 0xc0, 0x83, 0x3f, 0x00, 0xc0, 0xc3, 0x7f, 0x00,
        0x80, 0xc1, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00,
        0x00, 0xe0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    static const uchar * const cursor_bits32[] = {
        vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
        0, 0, 0, 0, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits
    };

    static const uchar forbidden_bits[] = {
        0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01,
        0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06,
        0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03,
        0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00 };

    static const uchar forbiddenm_bits[] = {
        0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03,
        0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f,
        0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07,
        0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00};

    static const uchar openhand_bits[] = {
        0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
        0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
        0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
    static const uchar openhandm_bits[] = {
       0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
       0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
       0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
    static const uchar closedhand_bits[] = {
        0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
        0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
        0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
    static const uchar closedhandm_bits[] = {
        0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
        0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
        0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};

    static const uchar * const cursor_bits20[] = {
        forbidden_bits, forbiddenm_bits
    };

    if ((cshape >= Qt::SizeVerCursor && cshape < Qt::SizeAllCursor)
        || cshape == Qt::BlankCursor) {
        XColor bg, fg;
        bg.red   = 255 << 8;
        bg.green = 255 << 8;
        bg.blue  = 255 << 8;
        fg.red   = 0;
        fg.green = 0;
        fg.blue  = 0;
        int i = (cshape - Qt::SizeVerCursor) * 2;
        pm  = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char*>(cursor_bits16[i]), 16, 16);
        pmm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char*>(cursor_bits16[i + 1]), 16, 16);
        hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
    } else if ((cshape >= Qt::SplitVCursor && cshape <= Qt::SplitHCursor)
               || cshape == Qt::WhatsThisCursor || cshape == Qt::BusyCursor) {
        XColor bg, fg;
        bg.red   = 255 << 8;
        bg.green = 255 << 8;
        bg.blue  = 255 << 8;
        fg.red   = 0;
        fg.green = 0;
        fg.blue  = 0;
        int i = (cshape - Qt::SplitVCursor) * 2;
        pm  = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(cursor_bits32[i]), 32, 32);
        pmm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(cursor_bits32[i + 1]), 32, 32);
        int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor
                  || cshape == Qt::BusyCursor) ? 0 : 16;
        hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, hs, hs);
    } else if (cshape == Qt::ForbiddenCursor) {
        XColor bg, fg;
        bg.red   = 255 << 8;
        bg.green = 255 << 8;
        bg.blue  = 255 << 8;
        fg.red   = 0;
        fg.green = 0;
        fg.blue  = 0;
        int i = (cshape - Qt::ForbiddenCursor) * 2;
        pm  = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(cursor_bits20[i]), 20, 20);
        pmm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(cursor_bits20[i + 1]), 20, 20);
        hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 10, 10);
    } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
        XColor bg, fg;
        bg.red   = 255 << 8;
        bg.green = 255 << 8;
        bg.blue  = 255 << 8;
        fg.red   = 0;
        fg.green = 0;
        fg.blue  = 0;
        bool open = cshape == Qt::OpenHandCursor;
        pm  = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(open ? openhand_bits : closedhand_bits), 16, 16);
        pmm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(open ? openhandm_bits : closedhandm_bits), 16, 16);
        hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
    } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor
               || cshape == Qt::DragLinkCursor) {
        XColor bg, fg;
        bg.red   = 255 << 8;
        bg.green = 255 << 8;
        bg.blue  = 255 << 8;
        fg.red   = 0;
        fg.green = 0;
        fg.blue  = 0;
        QImage image = QApplicationPrivate::instance()->getPixmapCursor(cshape).toImage();
        pm = QX11PixmapData::createBitmapFromImage(image);
        pmm = QX11PixmapData::createBitmapFromImage(image.createAlphaMask().convertToFormat(QImage::Format_MonoLSB));
        hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
    }

    if (hcurs)
    {
#ifndef QT_NO_XFIXES
        if (X11->use_xfixes && X11->ptrXFixesSetCursorName)
            X11->ptrXFixesSetCursorName(dpy, hcurs, cursorNames[cshape]);
#endif /* ! QT_NO_XFIXES */
        return;
    }

#endif /* ! QT_USE_APPROXIMATE_CURSORS */

    uint sh;
    switch (cshape) {                        // map Q cursor to X cursor
    case Qt::ArrowCursor:
        sh = XC_left_ptr;
        break;
    case Qt::UpArrowCursor:
        sh = XC_center_ptr;
        break;
    case Qt::CrossCursor:
        sh = XC_crosshair;
        break;
    case Qt::WaitCursor:
        sh = XC_watch;
        break;
    case Qt::IBeamCursor:
        sh = XC_xterm;
        break;
    case Qt::SizeAllCursor:
        sh = XC_fleur;
        break;
    case Qt::PointingHandCursor:
        sh = XC_hand2;
        break;
#ifdef QT_USE_APPROXIMATE_CURSORS
    case Qt::SizeBDiagCursor:
        sh = XC_top_right_corner;
        break;
    case Qt::SizeFDiagCursor:
        sh = XC_bottom_right_corner;
        break;
    case Qt::BlankCursor:
        XColor bg, fg;
        bg.red   = 255 << 8;
        bg.green = 255 << 8;
        bg.blue  = 255 << 8;
        fg.red   = 0;
        fg.green = 0;
        fg.blue  = 0;
        pm  = XCreateBitmapFromData(dpy, rootwin, cur_blank_bits, 16, 16);
        pmm = XCreateBitmapFromData(dpy, rootwin, cur_blank_bits, 16, 16);
        hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
        return;
        break;
    case Qt::SizeVerCursor:
    case Qt::SplitVCursor:
        sh = XC_sb_v_double_arrow;
        break;
    case Qt::SizeHorCursor:
    case Qt::SplitHCursor:
        sh = XC_sb_h_double_arrow;
        break;
    case Qt::WhatsThisCursor:
        sh = XC_question_arrow;
        break;
    case Qt::ForbiddenCursor:
        sh = XC_circle;
        break;
    case Qt::BusyCursor:
        sh = XC_watch;
        break;
    case Qt::DragCopyCursor:
        sh = XC_tcross;
        break;
    case Qt::DragLinkCursor:
        sh = XC_center_ptr;
        break;
    case Qt::DragMoveCursor:
        sh = XC_top_left_arrow;
        break;
#endif /* QT_USE_APPROXIMATE_CURSORS */
    default:
        qWarning("QCursor::update: Invalid cursor shape %d", cshape);
        return;
    }
    hcurs = XCreateFontCursor(dpy, sh);

#ifndef QT_NO_XFIXES
    if (X11->use_xfixes && X11->ptrXFixesSetCursorName)
        X11->ptrXFixesSetCursorName(dpy, hcurs, cursorNames[cshape]);
#endif /* ! QT_NO_XFIXES */
}

QT_END_NAMESPACE
>rulePlaceholderExpander( this->LocalGenerator->CreateRulePlaceholderExpander()); // Construct the compile rules. { std::vector<std::string> compileCommands; if (lang == "CUDA") { std::string cmdVar; if (this->GeneratorTarget->GetPropertyAsBool( "CUDA_SEPARABLE_COMPILATION")) { cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION"; } else if (this->GeneratorTarget->GetPropertyAsBool( "CUDA_PTX_COMPILATION")) { cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION"; } else { cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION"; } const std::string& compileRule = this->Makefile->GetRequiredDefinition(cmdVar); cmExpandList(compileRule, compileCommands); } else { const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT"; const std::string& compileRule = this->Makefile->GetRequiredDefinition(cmdVar); cmExpandList(compileRule, compileCommands); } if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") && lang_can_export_cmds && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, compileCommand, vars); std::string workingDirectory = this->LocalGenerator->GetCurrentBinaryDirectory(); compileCommand.replace(compileCommand.find(langFlags), langFlags.size(), this->GetFlags(lang, this->GetConfigName())); std::string langDefines = std::string("$(") + lang + "_DEFINES)"; compileCommand.replace(compileCommand.find(langDefines), langDefines.size(), this->GetDefines(lang, this->GetConfigName())); std::string langIncludes = std::string("$(") + lang + "_INCLUDES)"; compileCommand.replace(compileCommand.find(langIncludes), langIncludes.size(), this->GetIncludes(lang, this->GetConfigName())); const char* eliminate[] = { this->Makefile->GetDefinition("CMAKE_START_TEMP_FILE"), this->Makefile->GetDefinition("CMAKE_END_TEMP_FILE") }; for (const char* el : eliminate) { if (el) { cmSystemTools::ReplaceString(compileCommand, el, ""); } } this->GlobalGenerator->AddCXXCompileCommand( source.GetFullPath(), workingDirectory, compileCommand); } // See if we need to use a compiler launcher like ccache or distcc std::string compilerLauncher; if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" || lang == "OBJC" || lang == "OBJCXX")) { std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); if (cmNonempty(clauncher)) { compilerLauncher = *clauncher; } } // Maybe insert an include-what-you-use runner. if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) { std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; cmProp iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); std::string const tidy_prop = lang + "_CLANG_TIDY"; cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop); std::string const cpplint_prop = lang + "_CPPLINT"; cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); std::string const cppcheck_prop = lang + "_CPPCHECK"; cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) || cmNonempty(cppcheck)) { std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile"; if (!compilerLauncher.empty()) { // In __run_co_compile case the launcher command is supplied // via --launcher=<maybe-list> and consumed run_iwyu += " --launcher="; run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); compilerLauncher.clear(); } if (cmNonempty(iwyu)) { run_iwyu += " --iwyu="; run_iwyu += this->LocalGenerator->EscapeForShell(*iwyu); } if (cmNonempty(tidy)) { run_iwyu += " --tidy="; const char* driverMode = this->Makefile->GetDefinition( "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE"); if (!cmNonempty(driverMode)) { driverMode = lang == "C" ? "gcc" : "g++"; } run_iwyu += this->LocalGenerator->EscapeForShell( cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); } if (cmNonempty(cpplint)) { run_iwyu += " --cpplint="; run_iwyu += this->LocalGenerator->EscapeForShell(*cpplint); } if (cmNonempty(cppcheck)) { run_iwyu += " --cppcheck="; run_iwyu += this->LocalGenerator->EscapeForShell(*cppcheck); } if (cmNonempty(tidy) || (cmNonempty(cpplint)) || (cmNonempty(cppcheck))) { run_iwyu += " --source="; run_iwyu += sourceFile; } run_iwyu += " -- "; compileCommands.front().insert(0, run_iwyu); } } // If compiler launcher was specified and not consumed above, it // goes to the beginning of the command line. if (!compileCommands.empty() && !compilerLauncher.empty()) { std::vector<std::string> args = cmExpandedList(compilerLauncher, true); if (!args.empty()) { args[0] = this->LocalGenerator->ConvertToOutputFormat( args[0], cmOutputConverter::SHELL); for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) { i = this->LocalGenerator->EscapeForShell(i); } } compileCommands.front().insert(0, cmJoin(args, " ") + " "); } std::string launcher; { const char* val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_COMPILE"); if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } } // Expand placeholders in the commands. for (std::string& compileCommand : compileCommands) { compileCommand = cmStrCat(launcher, compileCommand); rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, compileCommand, vars); } // Change the command working directory to the local build tree. this->LocalGenerator->CreateCDCommand( compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); cm::append(commands, compileCommands); } // Check for extra outputs created by the compilation. std::vector<std::string> outputs(1, relativeObj); if (cmProp extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) { std::string evaluated_outputs = cmGeneratorExpression::Evaluate( *extra_outputs_str, this->LocalGenerator, config); if (!evaluated_outputs.empty()) { // Register these as extra files to clean. cmExpandList(evaluated_outputs, outputs); this->CleanFiles.insert(outputs.begin() + 1, outputs.end()); } } // Write the rule. this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends, commands); bool do_preprocess_rules = lang_has_preprocessor && this->LocalGenerator->GetCreatePreprocessedSourceRules(); bool do_assembly_rules = lang_has_assembly && this->LocalGenerator->GetCreateAssemblySourceRules(); if (do_preprocess_rules || do_assembly_rules) { std::vector<std::string> force_depends; force_depends.emplace_back("cmake_force"); std::string::size_type dot_pos = relativeObj.rfind('.'); std::string relativeObjBase = relativeObj.substr(0, dot_pos); dot_pos = obj.rfind('.'); std::string objBase = obj.substr(0, dot_pos); if (do_preprocess_rules) { commands.clear(); std::string relativeObjI = relativeObjBase + ".i"; std::string objI = objBase + ".i"; std::string preprocessEcho = cmStrCat("Preprocessing ", lang, " source to ", objI); this->LocalGenerator->AppendEcho( commands, preprocessEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string preprocessRuleVar = cmStrCat("CMAKE_", lang, "_CREATE_PREPROCESSED_SOURCE"); if (const char* preprocessRule = this->Makefile->GetDefinition(preprocessRuleVar)) { std::vector<std::string> preprocessCommands = cmExpandedList(preprocessRule); std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat( objI, cmOutputConverter::SHELL); vars.PreprocessedSource = shellObjI.c_str(); // Expand placeholders in the commands. for (std::string& preprocessCommand : preprocessCommands) { // no launcher for preprocessor commands rulePlaceholderExpander->ExpandRuleVariables( this->LocalGenerator, preprocessCommand, vars); } this->LocalGenerator->CreateCDCommand( preprocessCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); cm::append(commands, preprocessCommands); } else { std::string cmd = cmStrCat("$(CMAKE_COMMAND) -E cmake_unimplemented_variable ", preprocessRuleVar); commands.push_back(std::move(cmd)); } this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, relativeObjI, force_depends, commands, false); } if (do_assembly_rules) { commands.clear(); std::string relativeObjS = relativeObjBase + ".s"; std::string objS = objBase + ".s"; std::string assemblyEcho = cmStrCat("Compiling ", lang, " source to assembly ", objS); this->LocalGenerator->AppendEcho( commands, assemblyEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string assemblyRuleVar = cmStrCat("CMAKE_", lang, "_CREATE_ASSEMBLY_SOURCE"); if (const char* assemblyRule = this->Makefile->GetDefinition(assemblyRuleVar)) { std::vector<std::string> assemblyCommands = cmExpandedList(assemblyRule); std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat( objS, cmOutputConverter::SHELL); vars.AssemblySource = shellObjS.c_str(); // Expand placeholders in the commands. for (std::string& assemblyCommand : assemblyCommands) { // no launcher for assembly commands rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, assemblyCommand, vars); } this->LocalGenerator->CreateCDCommand( assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); cm::append(commands, assemblyCommands); } else { std::string cmd = cmStrCat("$(CMAKE_COMMAND) -E cmake_unimplemented_variable ", assemblyRuleVar); commands.push_back(std::move(cmd)); } this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, relativeObjS, force_depends, commands, false); } } } void cmMakefileTargetGenerator::WriteTargetCleanRules() { std::vector<std::string> depends; std::vector<std::string> commands; // Construct the clean target name. std::string cleanTarget = cmStrCat( this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget), "/clean"); // Construct the clean command. this->LocalGenerator->AppendCleanCommand(commands, this->CleanFiles, this->GeneratorTarget); this->LocalGenerator->CreateCDCommand( commands, this->LocalGenerator->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); // Write the rule. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, cleanTarget, depends, commands, true); } bool cmMakefileTargetGenerator::WriteMakeRule( std::ostream& os, const char* comment, const std::vector<std::string>& outputs, const std::vector<std::string>& depends, const std::vector<std::string>& commands, bool in_help) { bool symbolic = false; if (outputs.empty()) { return symbolic; } // Check whether we need to bother checking for a symbolic output. bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark(); // Check whether the first output is marked as symbolic. if (need_symbolic) { if (cmSourceFile* sf = this->Makefile->GetSource(outputs[0])) { symbolic = sf->GetPropertyAsBool("SYMBOLIC"); } } // We always attach the actual commands to the first output. this->LocalGenerator->WriteMakeRule(os, comment, outputs[0], depends, commands, symbolic, in_help); // For single outputs, we are done. if (outputs.size() == 1) { return symbolic; } // For multiple outputs, make the extra ones depend on the first one. std::vector<std::string> const output_depends(1, outputs[0]); std::string binDir = this->LocalGenerator->GetBinaryDirectory(); for (std::string const& output : cmMakeRange(outputs).advance(1)) { // Touch the extra output so "make" knows that it was updated, // but only if the output was actually created. std::string const out = this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->MaybeConvertToRelativePath(binDir, output), cmOutputConverter::SHELL); std::vector<std::string> output_commands; bool o_symbolic = false; if (need_symbolic) { if (cmSourceFile* sf = this->Makefile->GetSource(output)) { o_symbolic = sf->GetPropertyAsBool("SYMBOLIC"); } } symbolic = symbolic && o_symbolic; if (!o_symbolic) { output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out); } this->LocalGenerator->WriteMakeRule(os, nullptr, output, output_depends, output_commands, o_symbolic, in_help); if (!o_symbolic) { // At build time, remove the first output if this one does not exist // so that "make" will rerun the real commands that create this one. MultipleOutputPairsType::value_type p(output, outputs[0]); this->MultipleOutputPairs.insert(p); } } return symbolic; } void cmMakefileTargetGenerator::WriteTargetDependRules() { // must write the targets depend info file std::string dir = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); this->InfoFileNameFull = cmStrCat(dir, "/DependInfo.cmake"); this->InfoFileNameFull = this->LocalGenerator->ConvertToFullPath(this->InfoFileNameFull); this->InfoFileStream = cm::make_unique<cmGeneratedFileStream>(this->InfoFileNameFull); if (!this->InfoFileStream) { return; } this->InfoFileStream->SetCopyIfDifferent(true); this->LocalGenerator->WriteDependLanguageInfo(*this->InfoFileStream, this->GeneratorTarget); // Store multiple output pairs in the depend info file. if (!this->MultipleOutputPairs.empty()) { /* clang-format off */ *this->InfoFileStream << "\n" << "# Pairs of files generated by the same build rule.\n" << "set(CMAKE_MULTIPLE_OUTPUT_PAIRS\n"; /* clang-format on */ for (auto const& pi : this->MultipleOutputPairs) { *this->InfoFileStream << " " << cmOutputConverter::EscapeForCMake(pi.first) << " " << cmOutputConverter::EscapeForCMake(pi.second) << "\n"; } *this->InfoFileStream << " )\n\n"; } // Store list of targets linked directly or transitively. { /* clang-format off */ *this->InfoFileStream << "\n" << "# Targets to which this target links.\n" << "set(CMAKE_TARGET_LINKED_INFO_FILES\n"; /* clang-format on */ std::vector<std::string> dirs = this->GetLinkedTargetDirectories(this->GetConfigName()); for (std::string const& d : dirs) { *this->InfoFileStream << " \"" << d << "/DependInfo.cmake\"\n"; } *this->InfoFileStream << " )\n"; } std::string const& working_dir = this->LocalGenerator->GetCurrentBinaryDirectory(); /* clang-format off */ *this->InfoFileStream << "\n" << "# Fortran module output directory.\n" << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" << this->GeneratorTarget->GetFortranModuleDirectory(working_dir) << "\")\n"; /* clang-format on */ // and now write the rule to use it std::vector<std::string> depends; std::vector<std::string> commands; // Construct the name of the dependency generation target. std::string depTarget = cmStrCat( this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget), "/depend"); // Add a command to call CMake to scan dependencies. CMake will // touch the corresponding depends file after scanning dependencies. std::ostringstream depCmd; // TODO: Account for source file properties and directory-level // definitions when scanning for dependencies. #if !defined(_WIN32) || defined(__CYGWIN__) // This platform supports symlinks, so cmSystemTools will translate // paths. Make sure PWD is set to the original name of the home // output directory to help cmSystemTools to create the same // translation table for the dependency scanning process. depCmd << "cd " << (this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->GetBinaryDirectory(), cmOutputConverter::SHELL)) << " && "; #endif // Generate a call this signature: // // cmake -E cmake_depends <generator> // <home-src-dir> <start-src-dir> // <home-out-dir> <start-out-dir> // <dep-info> --color=$(COLOR) // // This gives the dependency scanner enough information to recreate // the state of our local generator sufficiently for its needs. depCmd << "$(CMAKE_COMMAND) -E cmake_depends \"" << this->GlobalGenerator->GetName() << "\" " << this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->GetSourceDirectory(), cmOutputConverter::SHELL) << " " << this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->GetCurrentSourceDirectory(), cmOutputConverter::SHELL) << " " << this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->GetBinaryDirectory(), cmOutputConverter::SHELL) << " " << this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->GetCurrentBinaryDirectory(), cmOutputConverter::SHELL) << " " << this->LocalGenerator->ConvertToOutputFormat( cmSystemTools::CollapseFullPath(this->InfoFileNameFull), cmOutputConverter::SHELL); if (this->LocalGenerator->GetColorMakefile()) { depCmd << " --color=$(COLOR)"; } commands.push_back(depCmd.str()); // Make sure all custom command outputs in this target are built. if (this->CustomCommandDriver == OnDepends) { this->DriveCustomCommands(depends); } // Write the rule. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, depTarget, depends, commands, true); } void cmMakefileTargetGenerator::DriveCustomCommands( std::vector<std::string>& depends) { // Depend on all custom command outputs. std::vector<cmSourceFile*> sources; this->GeneratorTarget->GetSourceFiles( sources, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); for (cmSourceFile* source : sources) { if (cmCustomCommand* cc = source->GetCustomCommand()) { cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), this->LocalGenerator); cm::append(depends, ccg.GetOutputs()); } } } void cmMakefileTargetGenerator::WriteObjectDependRules( cmSourceFile const& source, std::vector<std::string>& depends) { // Create the list of dependencies known at cmake time. These are // shared between the object file and dependency scanning rule. depends.push_back(source.GetFullPath()); if (cmProp objectDeps = source.GetProperty("OBJECT_DEPENDS")) { cmExpandList(*objectDeps, depends); } } void cmMakefileTargetGenerator::GenerateCustomRuleFile( cmCustomCommandGenerator const& ccg) { // Collect the commands. std::vector<std::string> commands; std::string comment = this->LocalGenerator->ConstructComment(ccg); if (!comment.empty()) { // add in a progress call if needed this->NumberOfProgressActions++; if (!this->NoRuleMessages) { cmLocalUnixMakefileGenerator3::EchoProgress progress; this->MakeEchoProgress(progress); this->LocalGenerator->AppendEcho( commands, comment, cmLocalUnixMakefileGenerator3::EchoGenerate, &progress); } } // Now append the actual user-specified commands. std::ostringstream content; this->LocalGenerator->AppendCustomCommand( commands, ccg, this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory(), false, &content); // Collect the dependencies. std::vector<std::string> depends; this->LocalGenerator->AppendCustomDepend(depends, ccg); // Write the rule. const std::vector<std::string>& outputs = ccg.GetOutputs(); bool symbolic = this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends, commands); // If the rule has changed make sure the output is rebuilt. if (!symbolic) { this->GlobalGenerator->AddRuleHash(ccg.GetOutputs(), content.str()); } // Setup implicit dependency scanning. for (auto const& idi : ccg.GetCC().GetImplicitDepends()) { std::string objFullPath = cmSystemTools::CollapseFullPath( outputs[0], this->LocalGenerator->GetCurrentBinaryDirectory()); std::string srcFullPath = cmSystemTools::CollapseFullPath( idi.second, this->LocalGenerator->GetCurrentBinaryDirectory()); this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi.first, objFullPath, srcFullPath); } } void cmMakefileTargetGenerator::MakeEchoProgress( cmLocalUnixMakefileGenerator3::EchoProgress& progress) const { progress.Dir = cmStrCat(this->LocalGenerator->GetBinaryDirectory(), "/CMakeFiles"); std::ostringstream progressArg; progressArg << "$(CMAKE_PROGRESS_" << this->NumberOfProgressActions << ")"; progress.Arg = progressArg.str(); } void cmMakefileTargetGenerator::WriteObjectsVariable( std::string& variableName, std::string& variableNameExternal, bool useWatcomQuote) { // Write a make variable assignment that lists all objects for the // target. variableName = this->LocalGenerator->CreateMakeVariable( this->GeneratorTarget->GetName(), "_OBJECTS"); *this->BuildFileStream << "# Object files for target " << this->GeneratorTarget->GetName() << "\n" << variableName << " ="; std::string object; const char* lineContinue = this->Makefile->GetDefinition("CMAKE_MAKE_LINE_CONTINUE"); if (!lineContinue) { lineContinue = "\\"; } const char* pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION"); for (std::string const& obj : this->Objects) { if (cmSystemTools::StringEndsWith(obj, pchExtension)) { continue; } *this->BuildFileStream << " " << lineContinue << "\n"; *this->BuildFileStream << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath( obj, useWatcomQuote); } *this->BuildFileStream << "\n"; // Write a make variable assignment that lists all external objects // for the target. variableNameExternal = this->LocalGenerator->CreateMakeVariable( this->GeneratorTarget->GetName(), "_EXTERNAL_OBJECTS"); /* clang-format off */ *this->BuildFileStream << "\n" << "# External object files for target " << this->GeneratorTarget->GetName() << "\n" << variableNameExternal << " ="; /* clang-format on */ std::string currentBinDir = this->LocalGenerator->GetCurrentBinaryDirectory(); for (std::string const& obj : this->ExternalObjects) { object = this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, obj); *this->BuildFileStream << " " << lineContinue << "\n"; *this->BuildFileStream << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath( obj, useWatcomQuote); } *this->BuildFileStream << "\n" << "\n"; } class cmMakefileTargetGeneratorObjectStrings { public: cmMakefileTargetGeneratorObjectStrings(std::vector<std::string>& strings, cmOutputConverter* outputConverter, cmStateDirectory const& stateDir, std::string::size_type limit) : Strings(strings) , OutputConverter(outputConverter) , StateDir(stateDir) , LengthLimit(limit) { this->Space = ""; } void Feed(std::string const& obj) { // Construct the name of the next object. this->NextObject = this->OutputConverter->ConvertToOutputFormat( this->MaybeConvertToRelativePath(obj), cmOutputConverter::RESPONSE); // Roll over to next string if the limit will be exceeded. if (this->LengthLimit != std::string::npos && (this->CurrentString.length() + 1 + this->NextObject.length() > this->LengthLimit)) { this->Strings.push_back(this->CurrentString); this->CurrentString.clear(); this->Space = ""; } // Separate from previous object. this->CurrentString += this->Space; this->Space = " "; // Append this object. this->CurrentString += this->NextObject; } void Done() { this->Strings.push_back(this->CurrentString); } private: std::string MaybeConvertToRelativePath(std::string const& obj) { if (!this->StateDir.ContainsBoth(this->StateDir.GetCurrentBinary(), obj)) { return obj; } return cmSystemTools::ForceToRelativePath( this->StateDir.GetCurrentBinary(), obj); } std::vector<std::string>& Strings; cmOutputConverter* OutputConverter; cmStateDirectory StateDir; std::string::size_type LengthLimit; std::string CurrentString; std::string NextObject; const char* Space; }; void cmMakefileTargetGenerator::WriteObjectsStrings( std::vector<std::string>& objStrings, std::string::size_type limit) { const char* pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION"); cmMakefileTargetGeneratorObjectStrings helper( objStrings, this->LocalGenerator, this->LocalGenerator->GetStateSnapshot().GetDirectory(), limit); for (std::string const& obj : this->Objects) { if (cmSystemTools::StringEndsWith(obj, pchExtension)) { continue; } helper.Feed(obj); } for (std::string const& obj : this->ExternalObjects) { helper.Feed(obj); } helper.Done(); } void cmMakefileTargetGenerator::WriteTargetDriverRule( const std::string& main_output, bool relink) { // Compute the name of the driver target. std::string dir = this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); std::string buildTargetRuleName = cmStrCat(dir, relink ? "/preinstall" : "/build"); buildTargetRuleName = this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetBinaryDirectory(), buildTargetRuleName); // Build the list of target outputs to drive. std::vector<std::string> depends; depends.push_back(main_output); const char* comment = nullptr; if (relink) { // Setup the comment for the preinstall driver. comment = "Rule to relink during preinstall."; } else { // Setup the comment for the main build driver. comment = "Rule to build all files generated by this target."; // Make sure all custom command outputs in this target are built. if (this->CustomCommandDriver == OnBuild) { this->DriveCustomCommands(depends); } // Make sure the extra files are built. cm::append(depends, this->ExtraFiles); } // Write the driver rule. std::vector<std::string> no_commands; this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, comment, buildTargetRuleName, depends, no_commands, true); } void cmMakefileTargetGenerator::AppendTargetDepends( std::vector<std::string>& depends) { // Static libraries never depend on anything for linking. if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { return; } // Loop over all library dependencies. const std::string& cfg = this->GetConfigName(); if (cmComputeLinkInformation* cli = this->GeneratorTarget->GetLinkInformation(cfg)) { cm::append(depends, cli->GetDepends()); } } void cmMakefileTargetGenerator::AppendObjectDepends( std::vector<std::string>& depends) { // Add dependencies on the compiled object files. std::string const& relPath = this->LocalGenerator->GetHomeRelativeOutputPath(); for (std::string const& obj : this->Objects) { std::string objTarget = cmStrCat(relPath, obj); depends.push_back(std::move(objTarget)); } // Add dependencies on the external object files. cm::append(depends, this->ExternalObjects); // Add a dependency on the rule file itself. this->LocalGenerator->AppendRuleDepend(depends, this->BuildFileNameFull.c_str()); } void cmMakefileTargetGenerator::AppendLinkDepends( std::vector<std::string>& depends, const std::string& linkLanguage) { this->AppendObjectDepends(depends); // Add dependencies on targets that must be built first. this->AppendTargetDepends(depends); // Add a dependency on the link definitions file, if any. if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi = this->GeneratorTarget->GetModuleDefinitionInfo( this->GetConfigName())) { for (cmSourceFile const* src : mdi->Sources) { depends.push_back(src->GetFullPath()); } } // Add a dependency on user-specified manifest files, if any. std::vector<cmSourceFile const*> manifest_srcs; this->GeneratorTarget->GetManifests(manifest_srcs, this->GetConfigName()); for (cmSourceFile const* manifest_src : manifest_srcs) { depends.push_back(manifest_src->GetFullPath()); } // Add user-specified dependencies. this->GeneratorTarget->GetLinkDepends(depends, this->GetConfigName(), linkLanguage); } std::string cmMakefileTargetGenerator::GetLinkRule( const std::string& linkRuleVar) { std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); if (this->GeneratorTarget->HasImplibGNUtoMS(this->GetConfigName())) { std::string ruleVar = cmStrCat("CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()), "_GNUtoMS_RULE"); if (const char* rule = this->Makefile->GetDefinition(ruleVar)) { linkRule += rule; } } return linkRule; } void cmMakefileTargetGenerator::CloseFileStreams() { this->BuildFileStream.reset(); this->InfoFileStream.reset(); this->FlagFileStream.reset(); } void cmMakefileTargetGenerator::CreateLinkScript( const char* name, std::vector<std::string> const& link_commands, std::vector<std::string>& makefile_commands, std::vector<std::string>& makefile_depends) { // Create the link script file. std::string linkScriptName = cmStrCat(this->TargetBuildDirectoryFull, '/', name); cmGeneratedFileStream linkScriptStream(linkScriptName); linkScriptStream.SetCopyIfDifferent(true); for (std::string const& link_command : link_commands) { // Do not write out empty commands or commands beginning in the // shell no-op ":". if (!link_command.empty() && link_command[0] != ':') { linkScriptStream << link_command << "\n"; } } // Create the makefile command to invoke the link script. std::string link_command = cmStrCat( "$(CMAKE_COMMAND) -E cmake_link_script ", this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetCurrentBinaryDirectory(), linkScriptName), cmOutputConverter::SHELL), " --verbose=$(VERBOSE)"); makefile_commands.push_back(std::move(link_command)); makefile_depends.push_back(std::move(linkScriptName)); } bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects( std::string const& l) const { // Check for an explicit setting one way or the other. std::string const responseVar = "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_OBJECTS"; if (const char* val = this->Makefile->GetDefinition(responseVar)) { if (*val) { return cmIsOn(val); } } // Check for a system limit. if (size_t const limit = cmSystemTools::CalculateCommandLineLengthLimit()) { // Compute the total length of our list of object files with room // for argument separation and quoting. This does not convert paths // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the // actual list will likely be much shorter than this. However, in the // worst case all objects will remain as absolute paths. size_t length = 0; for (std::string const& obj : this->Objects) { length += obj.size() + 3; } for (std::string const& ext_obj : this->ExternalObjects) { length += ext_obj.size() + 3; } // We need to guarantee room for both objects and libraries, so // if the objects take up more than half then use a response file // for them. if (length > (limit / 2)) { return true; } } // We do not need a response file for objects. return false; } bool cmMakefileTargetGenerator::CheckUseResponseFileForLibraries( std::string const& l) const { // Check for an explicit setting one way or the other. std::string const responseVar = "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_LIBRARIES"; if (const char* val = this->Makefile->GetDefinition(responseVar)) { if (*val) { return cmIsOn(val); } } // We do not need a response file for libraries. return false; } std::string cmMakefileTargetGenerator::CreateResponseFile( const char* name, std::string const& options, std::vector<std::string>& makefile_depends) { // Create the response file. std::string responseFileNameFull = cmStrCat(this->TargetBuildDirectoryFull, '/', name); cmGeneratedFileStream responseStream(responseFileNameFull); responseStream.SetCopyIfDifferent(true); responseStream << options << "\n"; // Add a dependency so the target will rebuild when the set of // objects changes. makefile_depends.push_back(std::move(responseFileNameFull)); // Construct the name to be used on the command line. std::string responseFileName = cmStrCat(this->TargetBuildDirectory, '/', name); return responseFileName; } std::unique_ptr<cmLinkLineComputer> cmMakefileTargetGenerator::CreateLinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) { if (this->Makefile->IsOn("MSVC60")) { return this->GlobalGenerator->CreateMSVC60LinkLineComputer(outputConverter, stateDir); } return this->GlobalGenerator->CreateLinkLineComputer(outputConverter, stateDir); } void cmMakefileTargetGenerator::CreateLinkLibs( cmLinkLineComputer* linkLineComputer, std::string& linkLibs, bool useResponseFile, std::vector<std::string>& makefile_depends) { std::string frameworkPath; std::string linkPath; cmComputeLinkInformation* pcli = this->GeneratorTarget->GetLinkInformation(this->GetConfigName()); this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath, linkPath); linkLibs = frameworkPath + linkPath + linkLibs; if (useResponseFile && linkLibs.find_first_not_of(' ') != std::string::npos) { // Lookup the response file reference flag. std::string responseFlagVar = cmStrCat("CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()), "_RESPONSE_FILE_LINK_FLAG"); const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar); if (!responseFlag) { responseFlag = "@"; } // Create this response file. std::string link_rsp = this->CreateResponseFile("linklibs.rsp", linkLibs, makefile_depends); // Reference the response file. linkLibs = cmStrCat(responseFlag, this->LocalGenerator->ConvertToOutputFormat( link_rsp, cmOutputConverter::SHELL)); } } void cmMakefileTargetGenerator::CreateObjectLists( bool useLinkScript, bool useArchiveRules, bool useResponseFile, std::string& buildObjs, std::vector<std::string>& makefile_depends, bool useWatcomQuote) { std::string variableName; std::string variableNameExternal; this->WriteObjectsVariable(variableName, variableNameExternal, useWatcomQuote); if (useResponseFile) { // MSVC response files cannot exceed 128K. std::string::size_type const responseFileLimit = 131000; // Construct the individual object list strings. std::vector<std::string> object_strings; this->WriteObjectsStrings(object_strings, responseFileLimit); // Lookup the response file reference flag. std::string responseFlagVar = cmStrCat("CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()), "_RESPONSE_FILE_LINK_FLAG"); const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar); if (!responseFlag) { responseFlag = "@"; } // Write a response file for each string. const char* sep = ""; for (unsigned int i = 0; i < object_strings.size(); ++i) { // Number the response files. char rsp[32]; sprintf(rsp, "objects%u.rsp", i + 1); // Create this response file. std::string objects_rsp = this->CreateResponseFile(rsp, object_strings[i], makefile_depends); // Separate from previous response file references. buildObjs += sep; sep = " "; // Reference the response file. buildObjs += responseFlag; buildObjs += this->LocalGenerator->ConvertToOutputFormat( objects_rsp, cmOutputConverter::SHELL); } } else if (useLinkScript) { if (!useArchiveRules) { std::vector<std::string> objStrings; this->WriteObjectsStrings(objStrings); buildObjs = objStrings[0]; } } else { buildObjs = cmStrCat("$(", variableName, ") $(", variableNameExternal, ')'); } } void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, const std::string& lang, const std::string& /*config*/) { std::string responseVar = cmStrCat("CMAKE_", lang, "_USE_RESPONSE_FILE_FOR_INCLUDES"); bool useResponseFile = this->Makefile->IsOn(responseVar); std::vector<std::string> includes; this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, lang, this->GetConfigName()); std::string includeFlags = this->LocalGenerator->GetIncludeFlags( includes, this->GeneratorTarget, lang, false, useResponseFile, this->GetConfigName()); if (includeFlags.empty()) { return; } if (useResponseFile) { std::string const responseFlagVar = "CMAKE_" + lang + "_RESPONSE_FILE_FLAG"; std::string responseFlag = this->Makefile->GetSafeDefinition(responseFlagVar); if (responseFlag.empty()) { responseFlag = "@"; } std::string name = cmStrCat("includes_", lang, ".rsp"); std::string arg = std::move(responseFlag) + this->CreateResponseFile(name.c_str(), includeFlags, this->FlagFileDepends[lang]); this->LocalGenerator->AppendFlags(flags, arg); } else { this->LocalGenerator->AppendFlags(flags, includeFlags); } } void cmMakefileTargetGenerator::GenDefFile( std::vector<std::string>& real_link_commands) { cmGeneratorTarget::ModuleDefinitionInfo const* mdi = this->GeneratorTarget->GetModuleDefinitionInfo(this->GetConfigName()); if (!mdi || !mdi->DefFileGenerated) { return; } std::string cmd = cmSystemTools::GetCMakeCommand(); cmd = cmStrCat( this->LocalGenerator->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL), " -E __create_def ", this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetCurrentBinaryDirectory(), mdi->DefFile), cmOutputConverter::SHELL), ' '); std::string objlist_file = mdi->DefFile + ".objs"; cmd += this->LocalGenerator->ConvertToOutputFormat( this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetCurrentBinaryDirectory(), objlist_file), cmOutputConverter::SHELL); const char* nm_executable = this->Makefile->GetDefinition("CMAKE_NM"); if (cmNonempty(nm_executable)) { cmd += " --nm="; cmd += this->LocalCommonGenerator->ConvertToOutputFormat( nm_executable, cmOutputConverter::SHELL); } real_link_commands.insert(real_link_commands.begin(), cmd); // create a list of obj files for the -E __create_def to read cmGeneratedFileStream fout(objlist_file); if (mdi->WindowsExportAllSymbols) { for (std::string const& obj : this->Objects) { if (cmHasLiteralSuffix(obj, ".obj")) { fout << obj << "\n"; } } for (std::string const& obj : this->ExternalObjects) { fout << obj << "\n"; } } for (cmSourceFile const* src : mdi->Sources) { fout << src->GetFullPath() << "\n"; } }