p4ruby 2022.1.2359956-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
data/ext/P4/extconf.rb ADDED
@@ -0,0 +1,634 @@
1
+ # File: extconf.rb
2
+
3
+ $:.push File.expand_path("../../../lib", __FILE__)
4
+
5
+ require 'mkmf'
6
+ require 'net/ftp'
7
+ require 'P4/version'
8
+ require 'rbconfig'
9
+ require 'openssl'
10
+
11
+ # Set this to the main version directory we look up in ftp.perforce.com for the P4API
12
+ # This is ignored if you specify the version on the command line.
13
+ # Changed the hardcoded string so that the version is now derived from version.rb file
14
+ #P4API_VERSION_DIR = 'r19.1'
15
+ def p4api_version_dir
16
+ ver=P4::Version.split(".")
17
+ p4_major = ver[0].chars.last(2).join
18
+ p4_minor = ver[1]
19
+ dir = "r" + p4_major + "." + p4_minor
20
+ end
21
+
22
+
23
+ #==============================================================================
24
+ # Provide platform variables in P4-specific format
25
+
26
+ def p4osplat
27
+ @p4osplat ||= calculate_p4osplat
28
+ end
29
+
30
+ def calculate_p4osplat
31
+ plat = RbConfig::CONFIG['arch'].split(/-/)[0].upcase
32
+
33
+ # On Mac OSX, fix the build to 64 bit arch
34
+ if p4osname == 'DARWIN'
35
+ plat = 'X86_64'
36
+ end
37
+
38
+ # Translate Ruby's arch names into Perforce's. Mostly the same so
39
+ # only the exceptions are handled here.
40
+ case plat
41
+ when /^I.86$/
42
+ plat = 'X86'
43
+ when /^AMD64$/
44
+ plat = 'X86_64'
45
+ when 'POWERPC'
46
+ plat = 'PPC'
47
+ end
48
+
49
+ return plat
50
+ end
51
+
52
+ def p4osname
53
+ @p4osname ||= calculate_p4osname
54
+ end
55
+
56
+ def calculate_p4osname
57
+ osname = RbConfig::CONFIG['arch'].split(/-/)[1].upcase
58
+ osname = osname.gsub(/MSWIN32(_\d+)?/, "NT")
59
+ osname = osname.split('-').shift
60
+
61
+ case osname
62
+ when /FREEBSD/
63
+ osname = 'FREEBSD'
64
+ when /DARWIN/
65
+ osname = 'DARWIN'
66
+ when /AIX/
67
+ osname = 'AIX'
68
+ when /SOLARIS/
69
+ osname = 'SOLARIS'
70
+ end
71
+
72
+ return osname
73
+ end
74
+
75
+ def p4osver
76
+ @p4osver ||= calculate_p4osver
77
+ end
78
+
79
+ def calculate_p4osver
80
+ ver = ''
81
+
82
+ case p4osname
83
+ when 'NT'
84
+ # do nothing
85
+ when /MINGW/
86
+ # do nothing
87
+ when /FREEBSD([0-9]+)/
88
+ ver = $1
89
+ when /DARWIN/
90
+ ver = CONFIG['arch'].upcase.gsub(/.*DARWIN(\d+).*/, '\1')
91
+ when /AIX(5)\.(\d)/
92
+ ver = $1 + $2
93
+ when /SOLARIS2\.(\d+)/
94
+ ver = $1
95
+ else
96
+ # use uname -r to see if it works
97
+ begin
98
+ ver=`uname -r`.chomp
99
+ ver_re = /^(\d+)\.(\d+)/
100
+ md = ver_re.match(ver)
101
+ if (md)
102
+ maj = md[1].to_i
103
+ min = md[2].to_i
104
+ ver = maj.to_s + min.to_s
105
+ end
106
+ rescue
107
+ # Nothing - if it failed, it failed.
108
+ end
109
+ end
110
+
111
+ return ver
112
+ end
113
+
114
+ def gcc
115
+ @gcc ||= calculate_gcc
116
+ end
117
+
118
+ def calculate_gcc
119
+ gcc = RbConfig::CONFIG["GCC"]
120
+ return gcc
121
+ end
122
+
123
+ def uname_platform
124
+ @uname_platform ||= calculate_uname_platform
125
+ end
126
+
127
+ def calculate_uname_platform
128
+ plat = "UNKNOWN"
129
+ begin
130
+ plat = `uname -p`
131
+ plat = plat.chomp.upcase
132
+ rescue
133
+ # Nothing - if it failed, it failed.
134
+ end
135
+ plat
136
+ end
137
+
138
+ #==============================================================================
139
+ # Setup additional compiler and linker options.
140
+ #
141
+ # We generally need to launch these things before we configure most of the flags.
142
+ # (See the main script at the end.)
143
+
144
+ def set_platform_opts
145
+
146
+ # Expand any embedded variables (like '$(CC)')
147
+ CONFIG["CC"] = RbConfig::CONFIG["CC"]
148
+ CONFIG["LDSHARED"] = RbConfig::CONFIG["LDSHARED"]
149
+
150
+ # Make sure we have a CXX value (sometimes there isn't one)
151
+ CONFIG["CXX"] = CONFIG["CC"] unless CONFIG.has_key?("CXX")
152
+
153
+ # O/S specific oddities
154
+
155
+ case p4osname
156
+ when /DARWIN/
157
+ CONFIG['CC'] = 'xcrun c++'
158
+ CONFIG['CXX'] = 'xcrun c++'
159
+ CONFIG['LDSHARED'] = CONFIG['CXX'] + ' -bundle'
160
+ when /FREEBSD/, /LINUX/
161
+ # FreeBSD 6 and some Linuxes use 'cc' for linking by default. The
162
+ # gcc detection patterns above won't catch that, so for these
163
+ # platforms, we specifically convert cc to c++.
164
+ CONFIG['LDSHARED'].sub!(/^cc/, 'c++')
165
+ when /MINGW32/, /MINGW/
166
+ # When building with MinGW we need to statically link libgcc
167
+ # and make sure we're linking with gcc and not g++. On older
168
+ # Rubies, they use LDSHARED; newer ones (>=1.9) use LDSHAREDXX
169
+ CONFIG['LDSHARED'].sub!(/g\+\+/, 'gcc')
170
+ CONFIG['LDSHAREDXX'].sub!(/g\+\+/, 'gcc')
171
+ CONFIG['LDSHARED'] = CONFIG['LDSHARED'] + ' -static-libgcc'
172
+ CONFIG['LDSHAREDXX'] = CONFIG['LDSHARED'] + ' -static-libgcc'
173
+ end
174
+ end
175
+
176
+ def set_platform_cxxflags
177
+ if (p4osname == 'LINUX') && (gcc == 'yes')
178
+ $CXXFLAGS += " -std=c++11 "
179
+ end
180
+ end
181
+
182
+
183
+ def set_platform_cppflags
184
+ $CPPFLAGS += "-DOS_#{p4osname} "
185
+ $CPPFLAGS += "-DOS_#{p4osname}#{p4osver} "
186
+ $CPPFLAGS += "-DOS_#{p4osname}#{p4osver}#{p4osplat} "
187
+
188
+ if (p4osname == 'NT')
189
+ $CPPFLAGS += '/DCASE_INSENSITIVE '
190
+ end
191
+
192
+ if (p4osname == 'MINGW32')
193
+ $CPPFLAGS += '-DOS_NT -DCASE_INSENSITIVE '
194
+ end
195
+
196
+ if (p4osname == 'MINGW')
197
+ $CPPFLAGS += '-DOS_NT -DCASE_INSENSITIVE '
198
+ end
199
+
200
+ if (p4osname == 'SOLARIS')
201
+ $CPPFLAGS += '-Dsolaris '
202
+ end
203
+
204
+ if (p4osname == 'DARWIN')
205
+ $CPPFLAGS += '-DCASE_INSENSITIVE '
206
+ end
207
+ end
208
+
209
+ def set_platform_cflags
210
+ if (p4osname == 'DARWIN')
211
+ # Only build for 64 bit if we have more than one arch defined in CFLAGS
212
+ $CFLAGS.slice!("-arch i386")
213
+ $CFLAGS.slice!("-arch ppc");
214
+ end
215
+ end
216
+
217
+ # Initialize the base sets of platform libraries *before other initializers*
218
+ # to preserve linking order.
219
+ def set_platform_libs
220
+
221
+ case p4osname
222
+ when 'SOLARIS'
223
+ osver = `uname -r`
224
+ osver.gsub!(/5\./, '2')
225
+ if (osver == '25')
226
+ $LDFLAGS += '/usr/ucblib/libucb.a '
227
+ end
228
+ have_library('nsl')
229
+ have_library('socket')
230
+ when 'NT'
231
+ have_library('advapi32')
232
+ have_library('wsock32')
233
+ have_library('kernel32')
234
+ have_library('oldnames')
235
+ when 'CYGWIN'
236
+ # Clear out 'bogus' libs on cygwin
237
+ CONFIG['LIBS'] = ''
238
+ when 'DARWIN'
239
+ if p4osver.to_i >= 8
240
+ # Only build for 64 bit if we have more than one arch defined in CFLAGS
241
+ $LDFLAGS.slice!('-arch i386')
242
+ $LDFLAGS.slice!('-arch ppc')
243
+ $LDFLAGS += ' -framework CoreFoundation -framework Foundation'
244
+ end
245
+ when 'LINUX', 'MINGW32', 'MINGW'
246
+ $LDFLAGS += ' -Wl,--allow-multiple-definition'
247
+ have_library('supc++')
248
+ end
249
+ end
250
+
251
+ #==============================================================================
252
+ # Manage p4api version
253
+ #
254
+ # The p4ruby implementation has some branching to support different versions
255
+ # of the C++ API. So we need to generate a p4rubyconf.h file that will setup
256
+ # this #define based branching based on the C++ API being compiled against.
257
+
258
+ # This captures the version information of the P4API C++ library we're building
259
+ # against. This is mostly parsed into this structure and then spit out into
260
+ # a header file we compile into the Ruby API.
261
+ class P4ApiVersion
262
+
263
+ def P4ApiVersion.load(dir)
264
+ #
265
+ # 2007.2 and later APIs put the Version file in the 'sample'
266
+ # subdirectory. Look there if we can't find it in the API root
267
+ #
268
+ ver_file = dir + "/Version"
269
+ unless File.exists?(ver_file)
270
+ ver_file = dir + "/sample/Version"
271
+ return nil unless File.exists?(ver_file)
272
+ end
273
+
274
+ re = Regexp.new('^RELEASE = (\d+)\s+(\d+)\s+(\w*\S*)\s*;')
275
+ rp = Regexp.new('^PATCHLEVEL = (.*)\s*;')
276
+ rs = Regexp.new('^SUPPDATE = (.*)\s*;')
277
+
278
+ p4api_version = nil
279
+
280
+ File.open(ver_file, "r") do
281
+ |f|
282
+ f.each_line do
283
+ |line|
284
+ if md = re.match(line)
285
+ p4api_version = P4ApiVersion.new(md[1], md[2])
286
+ p4api_version.set_type(md[3])
287
+ elsif md = rp.match(line)
288
+ p4api_version.patchlevel = md[1]
289
+ elsif md = rs.match(line)
290
+ p4api_version.suppdate = md[1]
291
+ end
292
+ end
293
+ end
294
+ puts("Found #{p4api_version} Perforce API in #{dir}")
295
+ return p4api_version
296
+ end
297
+
298
+ def initialize(major, minor = nil)
299
+ if (major.kind_of?(String) && !minor)
300
+ if (major =~ /(\d+)\.(\d+)/)
301
+ major = $1
302
+ minor = $2
303
+ else
304
+ raise("Bad API version: #{major}")
305
+ end
306
+ end
307
+
308
+ @major = major.to_i
309
+ @minor = minor.to_i
310
+ @type = nil
311
+
312
+ @patchlevel = nil
313
+ @suppdate = nil
314
+ end
315
+
316
+ def set_type(type)
317
+ if (type.kind_of?(String))
318
+ @type = type
319
+ end
320
+ end
321
+
322
+ attr_accessor :patchlevel, :suppdate
323
+ attr_reader :major, :minor, :type
324
+
325
+ include Comparable
326
+
327
+ def to_s
328
+ if (@type and not @type.empty?)
329
+ "#{major}.#{minor}.#{@type.upcase}"
330
+ else
331
+ "#{major}.#{minor}"
332
+ end
333
+ end
334
+
335
+ def to_i
336
+ major << 8 | minor
337
+ end
338
+
339
+ def <=>(other)
340
+ hi = @major <=> other.major
341
+ lo = @minor <=> other.minor
342
+
343
+ return hi == 0 ? lo : hi
344
+ end
345
+ end
346
+
347
+ def macro_def(macro, value, string=true)
348
+ if (string)
349
+ %Q{#define #{macro}\t"#{value}"}
350
+ else
351
+ %Q{#define #{macro}\t#{value}}
352
+ end
353
+ end
354
+
355
+ def create_p4rubyconf_header(p4api_version, libs)
356
+ File.open("p4rubyconf.h", "w") do
357
+ |ch|
358
+ ch.puts(macro_def("P4APIVER_STRING", p4api_version.to_s))
359
+ ch.puts(macro_def("P4APIVER_ID", p4api_version.to_i, false))
360
+ ch.puts(macro_def("P4API_PATCHLEVEL", p4api_version.patchlevel, false))
361
+ ch.puts(macro_def("P4API_PATCHLEVEL_STRING", p4api_version.patchlevel.to_s))
362
+ ch.puts(macro_def("P4RUBY_VERSION", P4::VERSION))
363
+ ch.puts(macro_def("WITH_LIBS", libs, true))
364
+ end
365
+ end
366
+
367
+ #==============================================================================
368
+ # P4API (C++ API) Helpers
369
+ #
370
+ # We do not have system installers yet, so allow most people to just get a
371
+ # version downloaded if since they very likely do not care about it.
372
+
373
+ # If the user has *not* specified --with-p4api-dir, check the --enable-p4api-download
374
+ # flag, and download the p4api before proceeding, unless that's disabled.
375
+ #
376
+ # This may be a little confusing. If people specify --with-p4api-dir, we want
377
+ # use only use that setting. If that setting is wrong, we want to fail.
378
+ #
379
+ # If they don't set the --with-p4api-dir, we'll proceed as if --enable-p4api-download
380
+ # has been set. Otherwise, they can --disable-p4api-download to ensure we
381
+ # just don't bother doing anything.
382
+ def resolve_p4api_dir
383
+ p4api_dir = nil
384
+
385
+ # When running rake compile, use this instead of other options, I'm not sure how
386
+ # gem/bundler options are passed through via rake
387
+ if ENV.has_key?('p4api_dir')
388
+ p4api_dir = ENV['p4api_dir']
389
+ dir_config('p4api', "#{p4api_dir}/include", "#{p4api_dir}/lib")
390
+ end
391
+
392
+ if !p4api_dir && !with_config('p4api-dir') && enable_config('p4api-download', true)
393
+ download_api_via_ftp
394
+ unzip_file
395
+ p4api_dir = downloaded_p4api_dir
396
+ dir_config('p4api', "#{p4api_dir}/include", "#{p4api_dir}/lib")
397
+ elsif with_config('p4api_dir')
398
+ p4api_dir = with_config('p4api-dir')
399
+ dir_config('p4api', "#{p4api_dir}/include", "#{p4api_dir}/lib")
400
+ elsif !p4api_dir
401
+ raise '--with-p4api-dir option has not been specified, and --disable-p4api-download is in effect'
402
+ end
403
+
404
+ p4api_dir
405
+ end
406
+
407
+ def resolve_ssl_dirs
408
+ ssl_dir = nil
409
+ # When running rake compile, use this instead of other options, I'm not sure how
410
+ # gem/bundler options are passed through via rake
411
+ if ENV.has_key?('ssl_dir')
412
+ ssl_dir = ENV['ssl_dir']
413
+ dir_config('ssl', "#{ssl_dir}/include", "#{ssl_dir}/lib")
414
+ puts "SSL Path #{ssl_dir}"
415
+ end
416
+ if ENV.has_key?('ssl_include_dir') && ENV.has_key?('ssl_lib_dir')
417
+ ssl_include_dir = ENV['ssl_include_dir']
418
+ ssl_lib_dir = ENV['ssl_lib_dir']
419
+ dir_config('ssl', ssl_include_dir, ssl_lib_dir)
420
+ puts "SSL Includes #{ssl_include_dir} Lib #{ssl_lib_dir}"
421
+ end
422
+ ssl_dir
423
+ end
424
+
425
+ # Our 'cpu' label we use as part of the directory name on ftp.perforce.com
426
+ def p4_cpu(os)
427
+ cpu = RbConfig::CONFIG['target_cpu']
428
+ case os
429
+ when :darwin, :linux
430
+ if cpu =~ /i686/
431
+ 'x86'
432
+ elsif cpu =~ /universal/
433
+ 'x86_64'
434
+ else
435
+ cpu
436
+ end
437
+ else
438
+ case cpu
439
+ when /ia/i
440
+ 'ia64'
441
+ else
442
+ cpu
443
+ end
444
+ end
445
+ end
446
+
447
+ # The p4_platform is our label that basically ends up being part of the
448
+ # directory name where we can download files from.
449
+ def p4_platform_label
450
+ case RbConfig::CONFIG["target_os"].downcase
451
+ when /nt|mswin|mingw|cygwin|msys/
452
+ # Ruby on windows is only MinGW via Rubyinstaller.org, though this may
453
+ # not work on all rubies.
454
+ # There are too many permutations of Windows p4api, to automate.
455
+ raise 'Automatic fetching of p4api from perforce FTP is not supported on Windows'
456
+ when /darwin19|darwin[2-9][0-9]/
457
+ "macosx1015#{p4_cpu(:darwin)}"
458
+ when /darwin/
459
+ "darwin90#{p4_cpu(:darwin)}"
460
+ when /solaris/
461
+ "solaris10#{p4_cpu(:solaris)}"
462
+ when /linux/
463
+ "linux26#{p4_cpu(:linux)}"
464
+ end
465
+ end
466
+
467
+ def platform_dir_name
468
+ "bin.#{p4_platform_label}"
469
+ end
470
+
471
+ def ftp_download_dir(version)
472
+ "perforce/#{version}/#{platform_dir_name}"
473
+ end
474
+
475
+ def filename
476
+ openssl_number = OpenSSL::OPENSSL_VERSION.split(' ')[1].to_s
477
+ openssl_number = openssl_number.slice(0, (openssl_number.rindex('.')))
478
+
479
+ if RbConfig::CONFIG['target_os'].downcase =~ /nt|mswin|mingw/
480
+ filename = 'p4api.zip'
481
+ if !openssl_number.to_s.empty?
482
+ case openssl_number.to_s
483
+ when /1.1/
484
+ filename = 'p4api-openssl1.1.1.zip'
485
+ when /1.0/
486
+ filename = 'p4api-openssl1.0.2.zip'
487
+ end
488
+ end
489
+ elsif RbConfig::CONFIG['target_os'].downcase =~ /darwin19|darwin[2-9][0-9]/
490
+ filename = 'p4api-openssl1.1.1.tgz'
491
+ else
492
+ filename = 'p4api.tgz'
493
+ if !openssl_number.to_s.empty?
494
+ case openssl_number.to_s
495
+ when /1.1/
496
+ filename = 'p4api-glibc2.3-openssl1.1.1.tgz'
497
+ when /1.0/
498
+ filename = 'p4api-glibc2.3-openssl1.0.2.tgz'
499
+ end
500
+ end
501
+ end
502
+ return filename
503
+ end
504
+
505
+
506
+ def remote_files_matching(ftp, dir, regex)
507
+ ftp.ls(dir.to_s).map { |entry|
508
+ if match = entry.match(regex)
509
+ yield match
510
+ else
511
+ nil
512
+ end
513
+ }.reject { |entry|
514
+ entry.nil?
515
+ }
516
+ end
517
+
518
+ def find_latest_with_p4api(ftp, versions)
519
+ versions.reverse_each { |v|
520
+ begin
521
+ remote_files_matching(ftp, "r#{v}/#{platform_dir_name}/", /p4api/) do
522
+ return v
523
+ end
524
+ rescue
525
+ next
526
+ end
527
+ }
528
+ end
529
+
530
+ def find_latest_version_dir(ftp)
531
+ ftp.chdir('perforce')
532
+
533
+ # Capture all versions
534
+ versions = remote_files_matching(ftp, '.', /r(1\d\.\d)/) { |m| m.captures.first }.sort
535
+
536
+ version = find_latest_with_p4api(ftp, versions)
537
+
538
+ ftp.chdir('..')
539
+
540
+ "r#{version}"
541
+ end
542
+
543
+ # Downloads the C++ P4API via FTP to the local directory, then 'initializes' it
544
+ # by unpacking it.
545
+ def download_api_via_ftp
546
+ ftp = Net::FTP.new('ftp.perforce.com')
547
+ ftp.passive=true
548
+ ftp.login
549
+
550
+ # At one point, we allowed the gem build to just find the most recent p4api build.
551
+ # P4Ruby probably shouldn't do that by default.
552
+ #version_dir = find_latest_version_dir(ftp)
553
+
554
+ dir = ftp_download_dir(p4api_version_dir)
555
+ ftp.chdir(dir)
556
+
557
+ puts "downloading #{filename} from #{dir} on ftp.perforce.com"
558
+ ftp.getbinaryfile(filename)
559
+
560
+ ensure
561
+ ftp.close if ftp and !ftp.closed?
562
+ end
563
+
564
+ def unzip_file
565
+ if RbConfig::CONFIG['target_os'].downcase =~ /nt|mswin|mingw/
566
+ `unzip #{filename}`
567
+ else
568
+ `tar xzf #{filename}`
569
+ end
570
+ end
571
+
572
+ def downloaded_p4api_dir
573
+ File.expand_path(Dir.entries('.').select { |x| x =~ /^p4api/ and File.directory?(x) }.first)
574
+ end
575
+
576
+ #==============================================================================
577
+ # Main script
578
+
579
+ puts "p4osname #{p4osname}"
580
+ puts "p4osver #{p4osver}"
581
+
582
+ # Specify different toolsets based on the platform type.
583
+ set_platform_opts
584
+
585
+ # We setup these flags in the beginning, before any libraries are detected,
586
+ # based solely on platform detection.
587
+ set_platform_cppflags
588
+ set_platform_cflags
589
+ set_platform_cxxflags
590
+
591
+ puts "$CPPFLAGS #{$CPPFLAGS}"
592
+ puts "$CFLAGS #{$CFLAGS}"
593
+ puts "$CXXFLAGS #{$CXXFLAGS}"
594
+
595
+ # Setup additional system library definitions based on platform type before
596
+ # we setup other libraries, in order to preserve linking order
597
+ set_platform_libs
598
+
599
+ puts "$LDFLAGS #{$LDFLAGS}"
600
+
601
+ p4api_dir = resolve_p4api_dir
602
+ puts "P4API Path #{p4api_dir}"
603
+
604
+ resolve_ssl_dirs
605
+
606
+ # If we happen to need SSL on Windows, we also need gdi32
607
+ if RbConfig::CONFIG['target_os'].downcase =~ /mingw/
608
+ have_library('gdi32') or raise
609
+ have_library('ole32') or raise
610
+ have_library('crypt32') or raise
611
+ end
612
+
613
+ have_library('crypto') or raise
614
+ have_library('ssl') or raise
615
+ have_library('supp') or raise
616
+ have_library('p4script_sqlite') or raise
617
+ have_library('p4script_curl') or raise
618
+ have_library('p4script') or raise
619
+ have_library('p4script_c') or raise
620
+ have_library('rpc') or raise
621
+ have_library('client') or raise
622
+
623
+ puts "$libs #{$libs}"
624
+
625
+ # Parse the Version file into a ruby structure
626
+ version_info = P4ApiVersion.load(p4api_dir)
627
+ create_p4rubyconf_header(version_info, $libs)
628
+
629
+ # This will generate a standard extconf.h based on what we discover locally.
630
+ # These are typically just 'yes I have such and such a library', which I
631
+ # don't believe we need to rely on actually.
632
+ create_header
633
+
634
+ create_makefile('P4')
data/ext/P4/gc_hack.h ADDED
@@ -0,0 +1,10 @@
1
+ /*******************************************************************************
2
+ * Hack to get garbage collection working reliably and portably.
3
+ ******************************************************************************/
4
+
5
+ #ifndef _GC_HACK_INCLUDED
6
+ # define _GC_HACK_INCLUDED
7
+
8
+ # define rb_gc_mark(value) ((void (*)(VALUE))(rb_gc_mark))(value)
9
+
10
+ #endif